1/* 2 * OpenRISC head.S 3 * 4 * Linux architectural port borrowing liberally from similar works of 5 * others. All original copyrights apply as per the original source 6 * declaration. 7 * 8 * Modifications for the OpenRISC architecture: 9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 10 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 15 * 2 of the License, or (at your option) any later version. 16 */ 17 18#include <linux/linkage.h> 19#include <linux/threads.h> 20#include <linux/errno.h> 21#include <linux/init.h> 22#include <linux/serial_reg.h> 23#include <asm/processor.h> 24#include <asm/page.h> 25#include <asm/mmu.h> 26#include <asm/pgtable.h> 27#include <asm/thread_info.h> 28#include <asm/cache.h> 29#include <asm/spr_defs.h> 30#include <asm/asm-offsets.h> 31#include <linux/of_fdt.h> 32 33#define tophys(rd,rs) \ 34 l.movhi rd,hi(-KERNELBASE) ;\ 35 l.add rd,rd,rs 36 37#define CLEAR_GPR(gpr) \ 38 l.movhi gpr,0x0 39 40#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ 41 l.movhi gpr,hi(symbol) ;\ 42 l.ori gpr,gpr,lo(symbol) 43 44 45#define UART_BASE_ADD 0x90000000 46 47#define EXCEPTION_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_SM) 48#define SYSCALL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_IEE | SPR_SR_TEE | SPR_SR_SM) 49 50/* ============================================[ tmp store locations ]=== */ 51 52#define SPR_SHADOW_GPR(x) ((x) + SPR_GPR_BASE + 32) 53 54/* 55 * emergency_print temporary stores 56 */ 57#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 58#define EMERGENCY_PRINT_STORE_GPR4 l.mtspr r0,r4,SPR_SHADOW_GPR(14) 59#define EMERGENCY_PRINT_LOAD_GPR4 l.mfspr r4,r0,SPR_SHADOW_GPR(14) 60 61#define EMERGENCY_PRINT_STORE_GPR5 l.mtspr r0,r5,SPR_SHADOW_GPR(15) 62#define EMERGENCY_PRINT_LOAD_GPR5 l.mfspr r5,r0,SPR_SHADOW_GPR(15) 63 64#define EMERGENCY_PRINT_STORE_GPR6 l.mtspr r0,r6,SPR_SHADOW_GPR(16) 65#define EMERGENCY_PRINT_LOAD_GPR6 l.mfspr r6,r0,SPR_SHADOW_GPR(16) 66 67#define EMERGENCY_PRINT_STORE_GPR7 l.mtspr r0,r7,SPR_SHADOW_GPR(7) 68#define EMERGENCY_PRINT_LOAD_GPR7 l.mfspr r7,r0,SPR_SHADOW_GPR(7) 69 70#define EMERGENCY_PRINT_STORE_GPR8 l.mtspr r0,r8,SPR_SHADOW_GPR(8) 71#define EMERGENCY_PRINT_LOAD_GPR8 l.mfspr r8,r0,SPR_SHADOW_GPR(8) 72 73#define EMERGENCY_PRINT_STORE_GPR9 l.mtspr r0,r9,SPR_SHADOW_GPR(9) 74#define EMERGENCY_PRINT_LOAD_GPR9 l.mfspr r9,r0,SPR_SHADOW_GPR(9) 75 76#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 77#define EMERGENCY_PRINT_STORE_GPR4 l.sw 0x20(r0),r4 78#define EMERGENCY_PRINT_LOAD_GPR4 l.lwz r4,0x20(r0) 79 80#define EMERGENCY_PRINT_STORE_GPR5 l.sw 0x24(r0),r5 81#define EMERGENCY_PRINT_LOAD_GPR5 l.lwz r5,0x24(r0) 82 83#define EMERGENCY_PRINT_STORE_GPR6 l.sw 0x28(r0),r6 84#define EMERGENCY_PRINT_LOAD_GPR6 l.lwz r6,0x28(r0) 85 86#define EMERGENCY_PRINT_STORE_GPR7 l.sw 0x2c(r0),r7 87#define EMERGENCY_PRINT_LOAD_GPR7 l.lwz r7,0x2c(r0) 88 89#define EMERGENCY_PRINT_STORE_GPR8 l.sw 0x30(r0),r8 90#define EMERGENCY_PRINT_LOAD_GPR8 l.lwz r8,0x30(r0) 91 92#define EMERGENCY_PRINT_STORE_GPR9 l.sw 0x34(r0),r9 93#define EMERGENCY_PRINT_LOAD_GPR9 l.lwz r9,0x34(r0) 94 95#endif 96 97/* 98 * TLB miss handlers temorary stores 99 */ 100#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 101#define EXCEPTION_STORE_GPR2 l.mtspr r0,r2,SPR_SHADOW_GPR(2) 102#define EXCEPTION_LOAD_GPR2 l.mfspr r2,r0,SPR_SHADOW_GPR(2) 103 104#define EXCEPTION_STORE_GPR3 l.mtspr r0,r3,SPR_SHADOW_GPR(3) 105#define EXCEPTION_LOAD_GPR3 l.mfspr r3,r0,SPR_SHADOW_GPR(3) 106 107#define EXCEPTION_STORE_GPR4 l.mtspr r0,r4,SPR_SHADOW_GPR(4) 108#define EXCEPTION_LOAD_GPR4 l.mfspr r4,r0,SPR_SHADOW_GPR(4) 109 110#define EXCEPTION_STORE_GPR5 l.mtspr r0,r5,SPR_SHADOW_GPR(5) 111#define EXCEPTION_LOAD_GPR5 l.mfspr r5,r0,SPR_SHADOW_GPR(5) 112 113#define EXCEPTION_STORE_GPR6 l.mtspr r0,r6,SPR_SHADOW_GPR(6) 114#define EXCEPTION_LOAD_GPR6 l.mfspr r6,r0,SPR_SHADOW_GPR(6) 115 116#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 117#define EXCEPTION_STORE_GPR2 l.sw 0x64(r0),r2 118#define EXCEPTION_LOAD_GPR2 l.lwz r2,0x64(r0) 119 120#define EXCEPTION_STORE_GPR3 l.sw 0x68(r0),r3 121#define EXCEPTION_LOAD_GPR3 l.lwz r3,0x68(r0) 122 123#define EXCEPTION_STORE_GPR4 l.sw 0x6c(r0),r4 124#define EXCEPTION_LOAD_GPR4 l.lwz r4,0x6c(r0) 125 126#define EXCEPTION_STORE_GPR5 l.sw 0x70(r0),r5 127#define EXCEPTION_LOAD_GPR5 l.lwz r5,0x70(r0) 128 129#define EXCEPTION_STORE_GPR6 l.sw 0x74(r0),r6 130#define EXCEPTION_LOAD_GPR6 l.lwz r6,0x74(r0) 131 132#endif 133 134/* 135 * EXCEPTION_HANDLE temporary stores 136 */ 137 138#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 139#define EXCEPTION_T_STORE_GPR30 l.mtspr r0,r30,SPR_SHADOW_GPR(30) 140#define EXCEPTION_T_LOAD_GPR30(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(30) 141 142#define EXCEPTION_T_STORE_GPR10 l.mtspr r0,r10,SPR_SHADOW_GPR(10) 143#define EXCEPTION_T_LOAD_GPR10(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(10) 144 145#define EXCEPTION_T_STORE_SP l.mtspr r0,r1,SPR_SHADOW_GPR(1) 146#define EXCEPTION_T_LOAD_SP(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(1) 147 148#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 149#define EXCEPTION_T_STORE_GPR30 l.sw 0x78(r0),r30 150#define EXCEPTION_T_LOAD_GPR30(reg) l.lwz reg,0x78(r0) 151 152#define EXCEPTION_T_STORE_GPR10 l.sw 0x7c(r0),r10 153#define EXCEPTION_T_LOAD_GPR10(reg) l.lwz reg,0x7c(r0) 154 155#define EXCEPTION_T_STORE_SP l.sw 0x80(r0),r1 156#define EXCEPTION_T_LOAD_SP(reg) l.lwz reg,0x80(r0) 157#endif 158 159/* =========================================================[ macros ]=== */ 160 161#ifdef CONFIG_SMP 162#define GET_CURRENT_PGD(reg,t1) \ 163 LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\ 164 l.mfspr t1,r0,SPR_COREID ;\ 165 l.slli t1,t1,2 ;\ 166 l.add reg,reg,t1 ;\ 167 tophys (t1,reg) ;\ 168 l.lwz reg,0(t1) 169#else 170#define GET_CURRENT_PGD(reg,t1) \ 171 LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\ 172 tophys (t1,reg) ;\ 173 l.lwz reg,0(t1) 174#endif 175 176/* Load r10 from current_thread_info_set - clobbers r1 and r30 */ 177#ifdef CONFIG_SMP 178#define GET_CURRENT_THREAD_INFO \ 179 LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\ 180 tophys (r30,r1) ;\ 181 l.mfspr r10,r0,SPR_COREID ;\ 182 l.slli r10,r10,2 ;\ 183 l.add r30,r30,r10 ;\ 184 /* r10: current_thread_info */ ;\ 185 l.lwz r10,0(r30) 186#else 187#define GET_CURRENT_THREAD_INFO \ 188 LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\ 189 tophys (r30,r1) ;\ 190 /* r10: current_thread_info */ ;\ 191 l.lwz r10,0(r30) 192#endif 193 194/* 195 * DSCR: this is a common hook for handling exceptions. it will save 196 * the needed registers, set up stack and pointer to current 197 * then jump to the handler while enabling MMU 198 * 199 * PRMS: handler - a function to jump to. it has to save the 200 * remaining registers to kernel stack, call 201 * appropriate arch-independant exception handler 202 * and finaly jump to ret_from_except 203 * 204 * PREQ: unchanged state from the time exception happened 205 * 206 * POST: SAVED the following registers original value 207 * to the new created exception frame pointed to by r1 208 * 209 * r1 - ksp pointing to the new (exception) frame 210 * r4 - EEAR exception EA 211 * r10 - current pointing to current_thread_info struct 212 * r12 - syscall 0, since we didn't come from syscall 213 * r30 - handler address of the handler we'll jump to 214 * 215 * handler has to save remaining registers to the exception 216 * ksp frame *before* tainting them! 217 * 218 * NOTE: this function is not reentrant per se. reentrancy is guaranteed 219 * by processor disabling all exceptions/interrupts when exception 220 * accours. 221 * 222 * OPTM: no need to make it so wasteful to extract ksp when in user mode 223 */ 224 225#define EXCEPTION_HANDLE(handler) \ 226 EXCEPTION_T_STORE_GPR30 ;\ 227 l.mfspr r30,r0,SPR_ESR_BASE ;\ 228 l.andi r30,r30,SPR_SR_SM ;\ 229 l.sfeqi r30,0 ;\ 230 EXCEPTION_T_STORE_GPR10 ;\ 231 l.bnf 2f /* kernel_mode */ ;\ 232 EXCEPTION_T_STORE_SP /* delay slot */ ;\ 2331: /* user_mode: */ ;\ 234 GET_CURRENT_THREAD_INFO ;\ 235 tophys (r30,r10) ;\ 236 l.lwz r1,(TI_KSP)(r30) ;\ 237 /* fall through */ ;\ 2382: /* kernel_mode: */ ;\ 239 /* create new stack frame, save only needed gprs */ ;\ 240 /* r1: KSP, r10: current, r4: EEAR, r31: __pa(KSP) */ ;\ 241 /* r12: temp, syscall indicator */ ;\ 242 l.addi r1,r1,-(INT_FRAME_SIZE) ;\ 243 /* r1 is KSP, r30 is __pa(KSP) */ ;\ 244 tophys (r30,r1) ;\ 245 l.sw PT_GPR12(r30),r12 ;\ 246 /* r4 use for tmp before EA */ ;\ 247 l.mfspr r12,r0,SPR_EPCR_BASE ;\ 248 l.sw PT_PC(r30),r12 ;\ 249 l.mfspr r12,r0,SPR_ESR_BASE ;\ 250 l.sw PT_SR(r30),r12 ;\ 251 /* save r30 */ ;\ 252 EXCEPTION_T_LOAD_GPR30(r12) ;\ 253 l.sw PT_GPR30(r30),r12 ;\ 254 /* save r10 as was prior to exception */ ;\ 255 EXCEPTION_T_LOAD_GPR10(r12) ;\ 256 l.sw PT_GPR10(r30),r12 ;\ 257 /* save PT_SP as was prior to exception */ ;\ 258 EXCEPTION_T_LOAD_SP(r12) ;\ 259 l.sw PT_SP(r30),r12 ;\ 260 /* save exception r4, set r4 = EA */ ;\ 261 l.sw PT_GPR4(r30),r4 ;\ 262 l.mfspr r4,r0,SPR_EEAR_BASE ;\ 263 /* r12 == 1 if we come from syscall */ ;\ 264 CLEAR_GPR(r12) ;\ 265 /* ----- turn on MMU ----- */ ;\ 266 /* Carry DSX into exception SR */ ;\ 267 l.mfspr r30,r0,SPR_SR ;\ 268 l.andi r30,r30,SPR_SR_DSX ;\ 269 l.ori r30,r30,(EXCEPTION_SR) ;\ 270 l.mtspr r0,r30,SPR_ESR_BASE ;\ 271 /* r30: EA address of handler */ ;\ 272 LOAD_SYMBOL_2_GPR(r30,handler) ;\ 273 l.mtspr r0,r30,SPR_EPCR_BASE ;\ 274 l.rfe 275 276/* 277 * this doesn't work 278 * 279 * 280 * #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION 281 * #define UNHANDLED_EXCEPTION(handler) \ 282 * l.ori r3,r0,0x1 ;\ 283 * l.mtspr r0,r3,SPR_SR ;\ 284 * l.movhi r3,hi(0xf0000100) ;\ 285 * l.ori r3,r3,lo(0xf0000100) ;\ 286 * l.jr r3 ;\ 287 * l.nop 1 288 * 289 * #endif 290 */ 291 292/* DSCR: this is the same as EXCEPTION_HANDLE(), we are just 293 * a bit more carefull (if we have a PT_SP or current pointer 294 * corruption) and set them up from 'current_set' 295 * 296 */ 297#define UNHANDLED_EXCEPTION(handler) \ 298 EXCEPTION_T_STORE_GPR30 ;\ 299 EXCEPTION_T_STORE_GPR10 ;\ 300 EXCEPTION_T_STORE_SP ;\ 301 /* temporary store r3, r9 into r1, r10 */ ;\ 302 l.addi r1,r3,0x0 ;\ 303 l.addi r10,r9,0x0 ;\ 304 /* the string referenced by r3 must be low enough */ ;\ 305 l.jal _emergency_print ;\ 306 l.ori r3,r0,lo(_string_unhandled_exception) ;\ 307 l.mfspr r3,r0,SPR_NPC ;\ 308 l.jal _emergency_print_nr ;\ 309 l.andi r3,r3,0x1f00 ;\ 310 /* the string referenced by r3 must be low enough */ ;\ 311 l.jal _emergency_print ;\ 312 l.ori r3,r0,lo(_string_epc_prefix) ;\ 313 l.jal _emergency_print_nr ;\ 314 l.mfspr r3,r0,SPR_EPCR_BASE ;\ 315 l.jal _emergency_print ;\ 316 l.ori r3,r0,lo(_string_nl) ;\ 317 /* end of printing */ ;\ 318 l.addi r3,r1,0x0 ;\ 319 l.addi r9,r10,0x0 ;\ 320 /* extract current, ksp from current_set */ ;\ 321 LOAD_SYMBOL_2_GPR(r1,_unhandled_stack_top) ;\ 322 LOAD_SYMBOL_2_GPR(r10,init_thread_union) ;\ 323 /* create new stack frame, save only needed gprs */ ;\ 324 /* r1: KSP, r10: current, r31: __pa(KSP) */ ;\ 325 /* r12: temp, syscall indicator, r13 temp */ ;\ 326 l.addi r1,r1,-(INT_FRAME_SIZE) ;\ 327 /* r1 is KSP, r30 is __pa(KSP) */ ;\ 328 tophys (r30,r1) ;\ 329 l.sw PT_GPR12(r30),r12 ;\ 330 l.mfspr r12,r0,SPR_EPCR_BASE ;\ 331 l.sw PT_PC(r30),r12 ;\ 332 l.mfspr r12,r0,SPR_ESR_BASE ;\ 333 l.sw PT_SR(r30),r12 ;\ 334 /* save r31 */ ;\ 335 EXCEPTION_T_LOAD_GPR30(r12) ;\ 336 l.sw PT_GPR30(r30),r12 ;\ 337 /* save r10 as was prior to exception */ ;\ 338 EXCEPTION_T_LOAD_GPR10(r12) ;\ 339 l.sw PT_GPR10(r30),r12 ;\ 340 /* save PT_SP as was prior to exception */ ;\ 341 EXCEPTION_T_LOAD_SP(r12) ;\ 342 l.sw PT_SP(r30),r12 ;\ 343 l.sw PT_GPR13(r30),r13 ;\ 344 /* --> */ ;\ 345 /* save exception r4, set r4 = EA */ ;\ 346 l.sw PT_GPR4(r30),r4 ;\ 347 l.mfspr r4,r0,SPR_EEAR_BASE ;\ 348 /* r12 == 1 if we come from syscall */ ;\ 349 CLEAR_GPR(r12) ;\ 350 /* ----- play a MMU trick ----- */ ;\ 351 l.ori r30,r0,(EXCEPTION_SR) ;\ 352 l.mtspr r0,r30,SPR_ESR_BASE ;\ 353 /* r31: EA address of handler */ ;\ 354 LOAD_SYMBOL_2_GPR(r30,handler) ;\ 355 l.mtspr r0,r30,SPR_EPCR_BASE ;\ 356 l.rfe 357 358/* =====================================================[ exceptions] === */ 359 360/* ---[ 0x100: RESET exception ]----------------------------------------- */ 361 .org 0x100 362 /* Jump to .init code at _start which lives in the .head section 363 * and will be discarded after boot. 364 */ 365 LOAD_SYMBOL_2_GPR(r15, _start) 366 tophys (r13,r15) /* MMU disabled */ 367 l.jr r13 368 l.nop 369 370/* ---[ 0x200: BUS exception ]------------------------------------------- */ 371 .org 0x200 372_dispatch_bus_fault: 373 EXCEPTION_HANDLE(_bus_fault_handler) 374 375/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ 376 .org 0x300 377_dispatch_do_dpage_fault: 378// totaly disable timer interrupt 379// l.mtspr r0,r0,SPR_TTMR 380// DEBUG_TLB_PROBE(0x300) 381// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x300) 382 EXCEPTION_HANDLE(_data_page_fault_handler) 383 384/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ 385 .org 0x400 386_dispatch_do_ipage_fault: 387// totaly disable timer interrupt 388// l.mtspr r0,r0,SPR_TTMR 389// DEBUG_TLB_PROBE(0x400) 390// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x400) 391 EXCEPTION_HANDLE(_insn_page_fault_handler) 392 393/* ---[ 0x500: Timer exception ]----------------------------------------- */ 394 .org 0x500 395 EXCEPTION_HANDLE(_timer_handler) 396 397/* ---[ 0x600: Alignment exception ]-------------------------------------- */ 398 .org 0x600 399 EXCEPTION_HANDLE(_alignment_handler) 400 401/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ 402 .org 0x700 403 EXCEPTION_HANDLE(_illegal_instruction_handler) 404 405/* ---[ 0x800: External interrupt exception ]---------------------------- */ 406 .org 0x800 407 EXCEPTION_HANDLE(_external_irq_handler) 408 409/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ 410 .org 0x900 411 l.j boot_dtlb_miss_handler 412 l.nop 413 414/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ 415 .org 0xa00 416 l.j boot_itlb_miss_handler 417 l.nop 418 419/* ---[ 0xb00: Range exception ]----------------------------------------- */ 420 .org 0xb00 421 UNHANDLED_EXCEPTION(_vector_0xb00) 422 423/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ 424 .org 0xc00 425 EXCEPTION_HANDLE(_sys_call_handler) 426 427/* ---[ 0xd00: Trap exception ]------------------------------------------ */ 428 .org 0xd00 429 UNHANDLED_EXCEPTION(_vector_0xd00) 430 431/* ---[ 0xe00: Trap exception ]------------------------------------------ */ 432 .org 0xe00 433// UNHANDLED_EXCEPTION(_vector_0xe00) 434 EXCEPTION_HANDLE(_trap_handler) 435 436/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ 437 .org 0xf00 438 UNHANDLED_EXCEPTION(_vector_0xf00) 439 440/* ---[ 0x1000: Reserved exception ]------------------------------------- */ 441 .org 0x1000 442 UNHANDLED_EXCEPTION(_vector_0x1000) 443 444/* ---[ 0x1100: Reserved exception ]------------------------------------- */ 445 .org 0x1100 446 UNHANDLED_EXCEPTION(_vector_0x1100) 447 448/* ---[ 0x1200: Reserved exception ]------------------------------------- */ 449 .org 0x1200 450 UNHANDLED_EXCEPTION(_vector_0x1200) 451 452/* ---[ 0x1300: Reserved exception ]------------------------------------- */ 453 .org 0x1300 454 UNHANDLED_EXCEPTION(_vector_0x1300) 455 456/* ---[ 0x1400: Reserved exception ]------------------------------------- */ 457 .org 0x1400 458 UNHANDLED_EXCEPTION(_vector_0x1400) 459 460/* ---[ 0x1500: Reserved exception ]------------------------------------- */ 461 .org 0x1500 462 UNHANDLED_EXCEPTION(_vector_0x1500) 463 464/* ---[ 0x1600: Reserved exception ]------------------------------------- */ 465 .org 0x1600 466 UNHANDLED_EXCEPTION(_vector_0x1600) 467 468/* ---[ 0x1700: Reserved exception ]------------------------------------- */ 469 .org 0x1700 470 UNHANDLED_EXCEPTION(_vector_0x1700) 471 472/* ---[ 0x1800: Reserved exception ]------------------------------------- */ 473 .org 0x1800 474 UNHANDLED_EXCEPTION(_vector_0x1800) 475 476/* ---[ 0x1900: Reserved exception ]------------------------------------- */ 477 .org 0x1900 478 UNHANDLED_EXCEPTION(_vector_0x1900) 479 480/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ 481 .org 0x1a00 482 UNHANDLED_EXCEPTION(_vector_0x1a00) 483 484/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ 485 .org 0x1b00 486 UNHANDLED_EXCEPTION(_vector_0x1b00) 487 488/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ 489 .org 0x1c00 490 UNHANDLED_EXCEPTION(_vector_0x1c00) 491 492/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ 493 .org 0x1d00 494 UNHANDLED_EXCEPTION(_vector_0x1d00) 495 496/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ 497 .org 0x1e00 498 UNHANDLED_EXCEPTION(_vector_0x1e00) 499 500/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ 501 .org 0x1f00 502 UNHANDLED_EXCEPTION(_vector_0x1f00) 503 504 .org 0x2000 505/* ===================================================[ kernel start ]=== */ 506 507/* .text*/ 508 509/* This early stuff belongs in HEAD, but some of the functions below definitely 510 * don't... */ 511 512 __HEAD 513 .global _start 514_start: 515 /* Init r0 to zero as per spec */ 516 CLEAR_GPR(r0) 517 518 /* save kernel parameters */ 519 l.or r25,r0,r3 /* pointer to fdt */ 520 521 /* 522 * ensure a deterministic start 523 */ 524 525 l.ori r3,r0,0x1 526 l.mtspr r0,r3,SPR_SR 527 528 CLEAR_GPR(r1) 529 CLEAR_GPR(r2) 530 CLEAR_GPR(r3) 531 CLEAR_GPR(r4) 532 CLEAR_GPR(r5) 533 CLEAR_GPR(r6) 534 CLEAR_GPR(r7) 535 CLEAR_GPR(r8) 536 CLEAR_GPR(r9) 537 CLEAR_GPR(r10) 538 CLEAR_GPR(r11) 539 CLEAR_GPR(r12) 540 CLEAR_GPR(r13) 541 CLEAR_GPR(r14) 542 CLEAR_GPR(r15) 543 CLEAR_GPR(r16) 544 CLEAR_GPR(r17) 545 CLEAR_GPR(r18) 546 CLEAR_GPR(r19) 547 CLEAR_GPR(r20) 548 CLEAR_GPR(r21) 549 CLEAR_GPR(r22) 550 CLEAR_GPR(r23) 551 CLEAR_GPR(r24) 552 CLEAR_GPR(r26) 553 CLEAR_GPR(r27) 554 CLEAR_GPR(r28) 555 CLEAR_GPR(r29) 556 CLEAR_GPR(r30) 557 CLEAR_GPR(r31) 558 559#ifdef CONFIG_SMP 560 l.mfspr r26,r0,SPR_COREID 561 l.sfeq r26,r0 562 l.bnf secondary_wait 563 l.nop 564#endif 565 /* 566 * set up initial ksp and current 567 */ 568 /* setup kernel stack */ 569 LOAD_SYMBOL_2_GPR(r1,init_thread_union + THREAD_SIZE) 570 LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current 571 tophys (r31,r10) 572 l.sw TI_KSP(r31), r1 573 574 l.ori r4,r0,0x0 575 576 577 /* 578 * .data contains initialized data, 579 * .bss contains uninitialized data - clear it up 580 */ 581clear_bss: 582 LOAD_SYMBOL_2_GPR(r24, __bss_start) 583 LOAD_SYMBOL_2_GPR(r26, _end) 584 tophys(r28,r24) 585 tophys(r30,r26) 586 CLEAR_GPR(r24) 587 CLEAR_GPR(r26) 5881: 589 l.sw (0)(r28),r0 590 l.sfltu r28,r30 591 l.bf 1b 592 l.addi r28,r28,4 593 594enable_ic: 595 l.jal _ic_enable 596 l.nop 597 598enable_dc: 599 l.jal _dc_enable 600 l.nop 601 602flush_tlb: 603 l.jal _flush_tlb 604 l.nop 605 606/* The MMU needs to be enabled before or32_early_setup is called */ 607 608enable_mmu: 609 /* 610 * enable dmmu & immu 611 * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0 612 */ 613 l.mfspr r30,r0,SPR_SR 614 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 615 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 616 l.or r30,r30,r28 617 l.mtspr r0,r30,SPR_SR 618 l.nop 619 l.nop 620 l.nop 621 l.nop 622 l.nop 623 l.nop 624 l.nop 625 l.nop 626 l.nop 627 l.nop 628 l.nop 629 l.nop 630 l.nop 631 l.nop 632 l.nop 633 l.nop 634 635 // reset the simulation counters 636 l.nop 5 637 638 /* check fdt header magic word */ 639 l.lwz r3,0(r25) /* load magic from fdt into r3 */ 640 l.movhi r4,hi(OF_DT_HEADER) 641 l.ori r4,r4,lo(OF_DT_HEADER) 642 l.sfeq r3,r4 643 l.bf _fdt_found 644 l.nop 645 /* magic number mismatch, set fdt pointer to null */ 646 l.or r25,r0,r0 647_fdt_found: 648 /* pass fdt pointer to or32_early_setup in r3 */ 649 l.or r3,r0,r25 650 LOAD_SYMBOL_2_GPR(r24, or32_early_setup) 651 l.jalr r24 652 l.nop 653 654clear_regs: 655 /* 656 * clear all GPRS to increase determinism 657 */ 658 CLEAR_GPR(r2) 659 CLEAR_GPR(r3) 660 CLEAR_GPR(r4) 661 CLEAR_GPR(r5) 662 CLEAR_GPR(r6) 663 CLEAR_GPR(r7) 664 CLEAR_GPR(r8) 665 CLEAR_GPR(r9) 666 CLEAR_GPR(r11) 667 CLEAR_GPR(r12) 668 CLEAR_GPR(r13) 669 CLEAR_GPR(r14) 670 CLEAR_GPR(r15) 671 CLEAR_GPR(r16) 672 CLEAR_GPR(r17) 673 CLEAR_GPR(r18) 674 CLEAR_GPR(r19) 675 CLEAR_GPR(r20) 676 CLEAR_GPR(r21) 677 CLEAR_GPR(r22) 678 CLEAR_GPR(r23) 679 CLEAR_GPR(r24) 680 CLEAR_GPR(r25) 681 CLEAR_GPR(r26) 682 CLEAR_GPR(r27) 683 CLEAR_GPR(r28) 684 CLEAR_GPR(r29) 685 CLEAR_GPR(r30) 686 CLEAR_GPR(r31) 687 688jump_start_kernel: 689 /* 690 * jump to kernel entry (start_kernel) 691 */ 692 LOAD_SYMBOL_2_GPR(r30, start_kernel) 693 l.jr r30 694 l.nop 695 696_flush_tlb: 697 /* 698 * I N V A L I D A T E T L B e n t r i e s 699 */ 700 LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) 701 LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) 702 l.addi r7,r0,128 /* Maximum number of sets */ 7031: 704 l.mtspr r5,r0,0x0 705 l.mtspr r6,r0,0x0 706 707 l.addi r5,r5,1 708 l.addi r6,r6,1 709 l.sfeq r7,r0 710 l.bnf 1b 711 l.addi r7,r7,-1 712 713 l.jr r9 714 l.nop 715 716#ifdef CONFIG_SMP 717secondary_wait: 718 /* Doze the cpu until we are asked to run */ 719 /* If we dont have power management skip doze */ 720 l.mfspr r25,r0,SPR_UPR 721 l.andi r25,r25,SPR_UPR_PMP 722 l.sfeq r25,r0 723 l.bf secondary_check_release 724 l.nop 725 726 /* Setup special secondary exception handler */ 727 LOAD_SYMBOL_2_GPR(r3, _secondary_evbar) 728 tophys(r25,r3) 729 l.mtspr r0,r25,SPR_EVBAR 730 731 /* Enable Interrupts */ 732 l.mfspr r25,r0,SPR_SR 733 l.ori r25,r25,SPR_SR_IEE 734 l.mtspr r0,r25,SPR_SR 735 736 /* Unmask interrupts interrupts */ 737 l.mfspr r25,r0,SPR_PICMR 738 l.ori r25,r25,0xffff 739 l.mtspr r0,r25,SPR_PICMR 740 741 /* Doze */ 742 l.mfspr r25,r0,SPR_PMR 743 LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME) 744 l.or r25,r25,r3 745 l.mtspr r0,r25,SPR_PMR 746 747 /* Wakeup - Restore exception handler */ 748 l.mtspr r0,r0,SPR_EVBAR 749 750secondary_check_release: 751 /* 752 * Check if we actually got the release signal, if not go-back to 753 * sleep. 754 */ 755 l.mfspr r25,r0,SPR_COREID 756 LOAD_SYMBOL_2_GPR(r3, secondary_release) 757 tophys(r4, r3) 758 l.lwz r3,0(r4) 759 l.sfeq r25,r3 760 l.bnf secondary_wait 761 l.nop 762 /* fall through to secondary_init */ 763 764secondary_init: 765 /* 766 * set up initial ksp and current 767 */ 768 LOAD_SYMBOL_2_GPR(r10, secondary_thread_info) 769 tophys (r30,r10) 770 l.lwz r10,0(r30) 771 l.addi r1,r10,THREAD_SIZE 772 tophys (r30,r10) 773 l.sw TI_KSP(r30),r1 774 775 l.jal _ic_enable 776 l.nop 777 778 l.jal _dc_enable 779 l.nop 780 781 l.jal _flush_tlb 782 l.nop 783 784 /* 785 * enable dmmu & immu 786 */ 787 l.mfspr r30,r0,SPR_SR 788 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 789 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 790 l.or r30,r30,r28 791 /* 792 * This is a bit tricky, we need to switch over from physical addresses 793 * to virtual addresses on the fly. 794 * To do that, we first set up ESR with the IME and DME bits set. 795 * Then EPCR is set to secondary_start and then a l.rfe is issued to 796 * "jump" to that. 797 */ 798 l.mtspr r0,r30,SPR_ESR_BASE 799 LOAD_SYMBOL_2_GPR(r30, secondary_start) 800 l.mtspr r0,r30,SPR_EPCR_BASE 801 l.rfe 802 803secondary_start: 804 LOAD_SYMBOL_2_GPR(r30, secondary_start_kernel) 805 l.jr r30 806 l.nop 807 808#endif 809 810/* ========================================[ cache ]=== */ 811 812 /* alignment here so we don't change memory offsets with 813 * memory controller defined 814 */ 815 .align 0x2000 816 817_ic_enable: 818 /* Check if IC present and skip enabling otherwise */ 819 l.mfspr r24,r0,SPR_UPR 820 l.andi r26,r24,SPR_UPR_ICP 821 l.sfeq r26,r0 822 l.bf 9f 823 l.nop 824 825 /* Disable IC */ 826 l.mfspr r6,r0,SPR_SR 827 l.addi r5,r0,-1 828 l.xori r5,r5,SPR_SR_ICE 829 l.and r5,r6,r5 830 l.mtspr r0,r5,SPR_SR 831 832 /* Establish cache block size 833 If BS=0, 16; 834 If BS=1, 32; 835 r14 contain block size 836 */ 837 l.mfspr r24,r0,SPR_ICCFGR 838 l.andi r26,r24,SPR_ICCFGR_CBS 839 l.srli r28,r26,7 840 l.ori r30,r0,16 841 l.sll r14,r30,r28 842 843 /* Establish number of cache sets 844 r16 contains number of cache sets 845 r28 contains log(# of cache sets) 846 */ 847 l.andi r26,r24,SPR_ICCFGR_NCS 848 l.srli r28,r26,3 849 l.ori r30,r0,1 850 l.sll r16,r30,r28 851 852 /* Invalidate IC */ 853 l.addi r6,r0,0 854 l.sll r5,r14,r28 855// l.mul r5,r14,r16 856// l.trap 1 857// l.addi r5,r0,IC_SIZE 8581: 859 l.mtspr r0,r6,SPR_ICBIR 860 l.sfne r6,r5 861 l.bf 1b 862 l.add r6,r6,r14 863 // l.addi r6,r6,IC_LINE 864 865 /* Enable IC */ 866 l.mfspr r6,r0,SPR_SR 867 l.ori r6,r6,SPR_SR_ICE 868 l.mtspr r0,r6,SPR_SR 869 l.nop 870 l.nop 871 l.nop 872 l.nop 873 l.nop 874 l.nop 875 l.nop 876 l.nop 877 l.nop 878 l.nop 8799: 880 l.jr r9 881 l.nop 882 883_dc_enable: 884 /* Check if DC present and skip enabling otherwise */ 885 l.mfspr r24,r0,SPR_UPR 886 l.andi r26,r24,SPR_UPR_DCP 887 l.sfeq r26,r0 888 l.bf 9f 889 l.nop 890 891 /* Disable DC */ 892 l.mfspr r6,r0,SPR_SR 893 l.addi r5,r0,-1 894 l.xori r5,r5,SPR_SR_DCE 895 l.and r5,r6,r5 896 l.mtspr r0,r5,SPR_SR 897 898 /* Establish cache block size 899 If BS=0, 16; 900 If BS=1, 32; 901 r14 contain block size 902 */ 903 l.mfspr r24,r0,SPR_DCCFGR 904 l.andi r26,r24,SPR_DCCFGR_CBS 905 l.srli r28,r26,7 906 l.ori r30,r0,16 907 l.sll r14,r30,r28 908 909 /* Establish number of cache sets 910 r16 contains number of cache sets 911 r28 contains log(# of cache sets) 912 */ 913 l.andi r26,r24,SPR_DCCFGR_NCS 914 l.srli r28,r26,3 915 l.ori r30,r0,1 916 l.sll r16,r30,r28 917 918 /* Invalidate DC */ 919 l.addi r6,r0,0 920 l.sll r5,r14,r28 9211: 922 l.mtspr r0,r6,SPR_DCBIR 923 l.sfne r6,r5 924 l.bf 1b 925 l.add r6,r6,r14 926 927 /* Enable DC */ 928 l.mfspr r6,r0,SPR_SR 929 l.ori r6,r6,SPR_SR_DCE 930 l.mtspr r0,r6,SPR_SR 9319: 932 l.jr r9 933 l.nop 934 935/* ===============================================[ page table masks ]=== */ 936 937#define DTLB_UP_CONVERT_MASK 0x3fa 938#define ITLB_UP_CONVERT_MASK 0x3a 939 940/* for SMP we'd have (this is a bit subtle, CC must be always set 941 * for SMP, but since we have _PAGE_PRESENT bit always defined 942 * we can just modify the mask) 943 */ 944#define DTLB_SMP_CONVERT_MASK 0x3fb 945#define ITLB_SMP_CONVERT_MASK 0x3b 946 947/* ---[ boot dtlb miss handler ]----------------------------------------- */ 948 949boot_dtlb_miss_handler: 950 951/* mask for DTLB_MR register: - (0) sets V (valid) bit, 952 * - (31-12) sets bits belonging to VPN (31-12) 953 */ 954#define DTLB_MR_MASK 0xfffff001 955 956/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit, 957 * - (4) sets A (access) bit, 958 * - (5) sets D (dirty) bit, 959 * - (8) sets SRE (superuser read) bit 960 * - (9) sets SWE (superuser write) bit 961 * - (31-12) sets bits belonging to VPN (31-12) 962 */ 963#define DTLB_TR_MASK 0xfffff332 964 965/* These are for masking out the VPN/PPN value from the MR/TR registers... 966 * it's not the same as the PFN */ 967#define VPN_MASK 0xfffff000 968#define PPN_MASK 0xfffff000 969 970 971 EXCEPTION_STORE_GPR6 972 973#if 0 974 l.mfspr r6,r0,SPR_ESR_BASE // 975 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 976 l.sfeqi r6,0 // r6 == 0x1 --> SM 977 l.bf exit_with_no_dtranslation // 978 l.nop 979#endif 980 981 /* this could be optimized by moving storing of 982 * non r6 registers here, and jumping r6 restore 983 * if not in supervisor mode 984 */ 985 986 EXCEPTION_STORE_GPR2 987 EXCEPTION_STORE_GPR3 988 EXCEPTION_STORE_GPR4 989 EXCEPTION_STORE_GPR5 990 991 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 992 993immediate_translation: 994 CLEAR_GPR(r6) 995 996 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 997 998 l.mfspr r6, r0, SPR_DMMUCFGR 999 l.andi r6, r6, SPR_DMMUCFGR_NTS 1000 l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF 1001 l.ori r5, r0, 0x1 1002 l.sll r5, r5, r6 // r5 = number DMMU sets 1003 l.addi r6, r5, -1 // r6 = nsets mask 1004 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1005 1006 l.or r6,r6,r4 // r6 <- r4 1007 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1008 l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000 1009 l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK 1010 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry 1011 l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR 1012 1013 /* set up DTLB with no translation for EA <= 0xbfffffff */ 1014 LOAD_SYMBOL_2_GPR(r6,0xbfffffff) 1015 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA) 1016 l.bf 1f // goto out 1017 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1018 1019 tophys(r3,r4) // r3 <- PA 10201: 1021 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1022 l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000 1023 l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK 1024 l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry 1025 l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR 1026 1027 EXCEPTION_LOAD_GPR6 1028 EXCEPTION_LOAD_GPR5 1029 EXCEPTION_LOAD_GPR4 1030 EXCEPTION_LOAD_GPR3 1031 EXCEPTION_LOAD_GPR2 1032 1033 l.rfe // SR <- ESR, PC <- EPC 1034 1035exit_with_no_dtranslation: 1036 /* EA out of memory or not in supervisor mode */ 1037 EXCEPTION_LOAD_GPR6 1038 EXCEPTION_LOAD_GPR4 1039 l.j _dispatch_bus_fault 1040 1041/* ---[ boot itlb miss handler ]----------------------------------------- */ 1042 1043boot_itlb_miss_handler: 1044 1045/* mask for ITLB_MR register: - sets V (valid) bit, 1046 * - sets bits belonging to VPN (15-12) 1047 */ 1048#define ITLB_MR_MASK 0xfffff001 1049 1050/* mask for ITLB_TR register: - sets A (access) bit, 1051 * - sets SXE (superuser execute) bit 1052 * - sets bits belonging to VPN (15-12) 1053 */ 1054#define ITLB_TR_MASK 0xfffff050 1055 1056/* 1057#define VPN_MASK 0xffffe000 1058#define PPN_MASK 0xffffe000 1059*/ 1060 1061 1062 1063 EXCEPTION_STORE_GPR2 1064 EXCEPTION_STORE_GPR3 1065 EXCEPTION_STORE_GPR4 1066 EXCEPTION_STORE_GPR5 1067 EXCEPTION_STORE_GPR6 1068 1069#if 0 1070 l.mfspr r6,r0,SPR_ESR_BASE // 1071 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 1072 l.sfeqi r6,0 // r6 == 0x1 --> SM 1073 l.bf exit_with_no_itranslation 1074 l.nop 1075#endif 1076 1077 1078 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1079 1080earlyearly: 1081 CLEAR_GPR(r6) 1082 1083 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1084 1085 l.mfspr r6, r0, SPR_IMMUCFGR 1086 l.andi r6, r6, SPR_IMMUCFGR_NTS 1087 l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF 1088 l.ori r5, r0, 0x1 1089 l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR 1090 l.addi r6, r5, -1 // r6 = nsets mask 1091 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1092 1093 l.or r6,r6,r4 // r6 <- r4 1094 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1095 l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000 1096 l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK 1097 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry 1098 l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR 1099 1100 /* 1101 * set up ITLB with no translation for EA <= 0x0fffffff 1102 * 1103 * we need this for head.S mapping (EA = PA). if we move all functions 1104 * which run with mmu enabled into entry.S, we might be able to eliminate this. 1105 * 1106 */ 1107 LOAD_SYMBOL_2_GPR(r6,0x0fffffff) 1108 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA) 1109 l.bf 1f // goto out 1110 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1111 1112 tophys(r3,r4) // r3 <- PA 11131: 1114 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1115 l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000 1116 l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK 1117 l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry 1118 l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR 1119 1120 EXCEPTION_LOAD_GPR6 1121 EXCEPTION_LOAD_GPR5 1122 EXCEPTION_LOAD_GPR4 1123 EXCEPTION_LOAD_GPR3 1124 EXCEPTION_LOAD_GPR2 1125 1126 l.rfe // SR <- ESR, PC <- EPC 1127 1128exit_with_no_itranslation: 1129 EXCEPTION_LOAD_GPR4 1130 EXCEPTION_LOAD_GPR6 1131 l.j _dispatch_bus_fault 1132 l.nop 1133 1134/* ====================================================================== */ 1135/* 1136 * Stuff below here shouldn't go into .head section... maybe this stuff 1137 * can be moved to entry.S ??? 1138 */ 1139 1140/* ==============================================[ DTLB miss handler ]=== */ 1141 1142/* 1143 * Comments: 1144 * Exception handlers are entered with MMU off so the following handler 1145 * needs to use physical addressing 1146 * 1147 */ 1148 1149 .text 1150ENTRY(dtlb_miss_handler) 1151 EXCEPTION_STORE_GPR2 1152 EXCEPTION_STORE_GPR3 1153 EXCEPTION_STORE_GPR4 1154 /* 1155 * get EA of the miss 1156 */ 1157 l.mfspr r2,r0,SPR_EEAR_BASE 1158 /* 1159 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1160 */ 1161 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r4 is temp 1162 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1163 l.slli r4,r4,0x2 // to get address << 2 1164 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1165 /* 1166 * if (pmd_none(*pmd)) 1167 * goto pmd_none: 1168 */ 1169 tophys (r4,r3) 1170 l.lwz r3,0x0(r4) // get *pmd value 1171 l.sfne r3,r0 1172 l.bnf d_pmd_none 1173 l.addi r3,r0,0xffffe000 // PAGE_MASK 1174 1175d_pmd_good: 1176 /* 1177 * pte = *pte_offset(pmd, daddr); 1178 */ 1179 l.lwz r4,0x0(r4) // get **pmd value 1180 l.and r4,r4,r3 // & PAGE_MASK 1181 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1182 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1183 l.slli r3,r3,0x2 // to get address << 2 1184 l.add r3,r3,r4 1185 l.lwz r3,0x0(r3) // this is pte at last 1186 /* 1187 * if (!pte_present(pte)) 1188 */ 1189 l.andi r4,r3,0x1 1190 l.sfne r4,r0 // is pte present 1191 l.bnf d_pte_not_present 1192 l.addi r4,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK 1193 /* 1194 * fill DTLB TR register 1195 */ 1196 l.and r4,r3,r4 // apply the mask 1197 // Determine number of DMMU sets 1198 l.mfspr r2, r0, SPR_DMMUCFGR 1199 l.andi r2, r2, SPR_DMMUCFGR_NTS 1200 l.srli r2, r2, SPR_DMMUCFGR_NTS_OFF 1201 l.ori r3, r0, 0x1 1202 l.sll r3, r3, r2 // r3 = number DMMU sets DMMUCFGR 1203 l.addi r2, r3, -1 // r2 = nsets mask 1204 l.mfspr r3, r0, SPR_EEAR_BASE 1205 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1206 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1207 //NUM_TLB_ENTRIES 1208 l.mtspr r2,r4,SPR_DTLBTR_BASE(0) 1209 /* 1210 * fill DTLB MR register 1211 */ 1212 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1213 l.ori r4,r3,0x1 // set hardware valid bit: DTBL_MR entry 1214 l.mtspr r2,r4,SPR_DTLBMR_BASE(0) 1215 1216 EXCEPTION_LOAD_GPR2 1217 EXCEPTION_LOAD_GPR3 1218 EXCEPTION_LOAD_GPR4 1219 l.rfe 1220d_pmd_none: 1221d_pte_not_present: 1222 EXCEPTION_LOAD_GPR2 1223 EXCEPTION_LOAD_GPR3 1224 EXCEPTION_LOAD_GPR4 1225 EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) 1226 1227/* ==============================================[ ITLB miss handler ]=== */ 1228ENTRY(itlb_miss_handler) 1229 EXCEPTION_STORE_GPR2 1230 EXCEPTION_STORE_GPR3 1231 EXCEPTION_STORE_GPR4 1232 /* 1233 * get EA of the miss 1234 */ 1235 l.mfspr r2,r0,SPR_EEAR_BASE 1236 1237 /* 1238 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1239 * 1240 */ 1241 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r5 is temp 1242 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1243 l.slli r4,r4,0x2 // to get address << 2 1244 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1245 /* 1246 * if (pmd_none(*pmd)) 1247 * goto pmd_none: 1248 */ 1249 tophys (r4,r3) 1250 l.lwz r3,0x0(r4) // get *pmd value 1251 l.sfne r3,r0 1252 l.bnf i_pmd_none 1253 l.addi r3,r0,0xffffe000 // PAGE_MASK 1254 1255i_pmd_good: 1256 /* 1257 * pte = *pte_offset(pmd, iaddr); 1258 * 1259 */ 1260 l.lwz r4,0x0(r4) // get **pmd value 1261 l.and r4,r4,r3 // & PAGE_MASK 1262 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1263 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1264 l.slli r3,r3,0x2 // to get address << 2 1265 l.add r3,r3,r4 1266 l.lwz r3,0x0(r3) // this is pte at last 1267 /* 1268 * if (!pte_present(pte)) 1269 * 1270 */ 1271 l.andi r4,r3,0x1 1272 l.sfne r4,r0 // is pte present 1273 l.bnf i_pte_not_present 1274 l.addi r4,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK 1275 /* 1276 * fill ITLB TR register 1277 */ 1278 l.and r4,r3,r4 // apply the mask 1279 l.andi r3,r3,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE 1280 l.sfeq r3,r0 1281 l.bf itlb_tr_fill //_workaround 1282 // Determine number of IMMU sets 1283 l.mfspr r2, r0, SPR_IMMUCFGR 1284 l.andi r2, r2, SPR_IMMUCFGR_NTS 1285 l.srli r2, r2, SPR_IMMUCFGR_NTS_OFF 1286 l.ori r3, r0, 0x1 1287 l.sll r3, r3, r2 // r3 = number IMMU sets IMMUCFGR 1288 l.addi r2, r3, -1 // r2 = nsets mask 1289 l.mfspr r3, r0, SPR_EEAR_BASE 1290 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1291 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1292 1293/* 1294 * __PHX__ :: fixme 1295 * we should not just blindly set executable flags, 1296 * but it does help with ping. the clean way would be to find out 1297 * (and fix it) why stack doesn't have execution permissions 1298 */ 1299 1300itlb_tr_fill_workaround: 1301 l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) 1302itlb_tr_fill: 1303 l.mtspr r2,r4,SPR_ITLBTR_BASE(0) 1304 /* 1305 * fill DTLB MR register 1306 */ 1307 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1308 l.ori r4,r3,0x1 // set hardware valid bit: ITBL_MR entry 1309 l.mtspr r2,r4,SPR_ITLBMR_BASE(0) 1310 1311 EXCEPTION_LOAD_GPR2 1312 EXCEPTION_LOAD_GPR3 1313 EXCEPTION_LOAD_GPR4 1314 l.rfe 1315 1316i_pmd_none: 1317i_pte_not_present: 1318 EXCEPTION_LOAD_GPR2 1319 EXCEPTION_LOAD_GPR3 1320 EXCEPTION_LOAD_GPR4 1321 EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) 1322 1323/* ==============================================[ boot tlb handlers ]=== */ 1324 1325 1326/* =================================================[ debugging aids ]=== */ 1327 1328 .align 64 1329_immu_trampoline: 1330 .space 64 1331_immu_trampoline_top: 1332 1333#define TRAMP_SLOT_0 (0x0) 1334#define TRAMP_SLOT_1 (0x4) 1335#define TRAMP_SLOT_2 (0x8) 1336#define TRAMP_SLOT_3 (0xc) 1337#define TRAMP_SLOT_4 (0x10) 1338#define TRAMP_SLOT_5 (0x14) 1339#define TRAMP_FRAME_SIZE (0x18) 1340 1341ENTRY(_immu_trampoline_workaround) 1342 // r2 EEA 1343 // r6 is physical EEA 1344 tophys(r6,r2) 1345 1346 LOAD_SYMBOL_2_GPR(r5,_immu_trampoline) 1347 tophys (r3,r5) // r3 is trampoline (physical) 1348 1349 LOAD_SYMBOL_2_GPR(r4,0x15000000) 1350 l.sw TRAMP_SLOT_0(r3),r4 1351 l.sw TRAMP_SLOT_1(r3),r4 1352 l.sw TRAMP_SLOT_4(r3),r4 1353 l.sw TRAMP_SLOT_5(r3),r4 1354 1355 // EPC = EEA - 0x4 1356 l.lwz r4,0x0(r6) // load op @ EEA + 0x0 (fc address) 1357 l.sw TRAMP_SLOT_3(r3),r4 // store it to _immu_trampoline_data 1358 l.lwz r4,-0x4(r6) // load op @ EEA - 0x4 (f8 address) 1359 l.sw TRAMP_SLOT_2(r3),r4 // store it to _immu_trampoline_data 1360 1361 l.srli r5,r4,26 // check opcode for write access 1362 l.sfeqi r5,0 // l.j 1363 l.bf 0f 1364 l.sfeqi r5,0x11 // l.jr 1365 l.bf 1f 1366 l.sfeqi r5,1 // l.jal 1367 l.bf 2f 1368 l.sfeqi r5,0x12 // l.jalr 1369 l.bf 3f 1370 l.sfeqi r5,3 // l.bnf 1371 l.bf 4f 1372 l.sfeqi r5,4 // l.bf 1373 l.bf 5f 137499: 1375 l.nop 1376 l.j 99b // should never happen 1377 l.nop 1 1378 1379 // r2 is EEA 1380 // r3 is trampoline address (physical) 1381 // r4 is instruction 1382 // r6 is physical(EEA) 1383 // 1384 // r5 1385 13862: // l.jal 1387 1388 /* 19 20 aa aa l.movhi r9,0xaaaa 1389 * a9 29 bb bb l.ori r9,0xbbbb 1390 * 1391 * where 0xaaaabbbb is EEA + 0x4 shifted right 2 1392 */ 1393 1394 l.addi r6,r2,0x4 // this is 0xaaaabbbb 1395 1396 // l.movhi r9,0xaaaa 1397 l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9 1398 l.sh (TRAMP_SLOT_0+0x0)(r3),r5 1399 l.srli r5,r6,16 1400 l.sh (TRAMP_SLOT_0+0x2)(r3),r5 1401 1402 // l.ori r9,0xbbbb 1403 l.ori r5,r0,0xa929 // 0xa929 == l.ori r9 1404 l.sh (TRAMP_SLOT_1+0x0)(r3),r5 1405 l.andi r5,r6,0xffff 1406 l.sh (TRAMP_SLOT_1+0x2)(r3),r5 1407 1408 /* falthrough, need to set up new jump offset */ 1409 1410 14110: // l.j 1412 l.slli r6,r4,6 // original offset shifted left 6 - 2 1413// l.srli r6,r6,6 // original offset shifted right 2 1414 1415 l.slli r4,r2,4 // old jump position: EEA shifted left 4 1416// l.srli r4,r4,6 // old jump position: shifted right 2 1417 1418 l.addi r5,r3,0xc // new jump position (physical) 1419 l.slli r5,r5,4 // new jump position: shifted left 4 1420 1421 // calculate new jump offset 1422 // new_off = old_off + (old_jump - new_jump) 1423 1424 l.sub r5,r4,r5 // old_jump - new_jump 1425 l.add r5,r6,r5 // orig_off + (old_jump - new_jump) 1426 l.srli r5,r5,6 // new offset shifted right 2 1427 1428 // r5 is new jump offset 1429 // l.j has opcode 0x0... 1430 l.sw TRAMP_SLOT_2(r3),r5 // write it back 1431 1432 l.j trampoline_out 1433 l.nop 1434 1435/* ----------------------------- */ 1436 14373: // l.jalr 1438 1439 /* 19 20 aa aa l.movhi r9,0xaaaa 1440 * a9 29 bb bb l.ori r9,0xbbbb 1441 * 1442 * where 0xaaaabbbb is EEA + 0x4 shifted right 2 1443 */ 1444 1445 l.addi r6,r2,0x4 // this is 0xaaaabbbb 1446 1447 // l.movhi r9,0xaaaa 1448 l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9 1449 l.sh (TRAMP_SLOT_0+0x0)(r3),r5 1450 l.srli r5,r6,16 1451 l.sh (TRAMP_SLOT_0+0x2)(r3),r5 1452 1453 // l.ori r9,0xbbbb 1454 l.ori r5,r0,0xa929 // 0xa929 == l.ori r9 1455 l.sh (TRAMP_SLOT_1+0x0)(r3),r5 1456 l.andi r5,r6,0xffff 1457 l.sh (TRAMP_SLOT_1+0x2)(r3),r5 1458 1459 l.lhz r5,(TRAMP_SLOT_2+0x0)(r3) // load hi part of jump instruction 1460 l.andi r5,r5,0x3ff // clear out opcode part 1461 l.ori r5,r5,0x4400 // opcode changed from l.jalr -> l.jr 1462 l.sh (TRAMP_SLOT_2+0x0)(r3),r5 // write it back 1463 1464 /* falthrough */ 1465 14661: // l.jr 1467 l.j trampoline_out 1468 l.nop 1469 1470/* ----------------------------- */ 1471 14724: // l.bnf 14735: // l.bf 1474 l.slli r6,r4,6 // original offset shifted left 6 - 2 1475// l.srli r6,r6,6 // original offset shifted right 2 1476 1477 l.slli r4,r2,4 // old jump position: EEA shifted left 4 1478// l.srli r4,r4,6 // old jump position: shifted right 2 1479 1480 l.addi r5,r3,0xc // new jump position (physical) 1481 l.slli r5,r5,4 // new jump position: shifted left 4 1482 1483 // calculate new jump offset 1484 // new_off = old_off + (old_jump - new_jump) 1485 1486 l.add r6,r6,r4 // (orig_off + old_jump) 1487 l.sub r6,r6,r5 // (orig_off + old_jump) - new_jump 1488 l.srli r6,r6,6 // new offset shifted right 2 1489 1490 // r6 is new jump offset 1491 l.lwz r4,(TRAMP_SLOT_2+0x0)(r3) // load jump instruction 1492 l.srli r4,r4,16 1493 l.andi r4,r4,0xfc00 // get opcode part 1494 l.slli r4,r4,16 1495 l.or r6,r4,r6 // l.b(n)f new offset 1496 l.sw TRAMP_SLOT_2(r3),r6 // write it back 1497 1498 /* we need to add l.j to EEA + 0x8 */ 1499 tophys (r4,r2) // may not be needed (due to shifts down_ 1500 l.addi r4,r4,(0x8 - 0x8) // jump target = r2 + 0x8 (compensate for 0x8) 1501 // jump position = r5 + 0x8 (0x8 compensated) 1502 l.sub r4,r4,r5 // jump offset = target - new_position + 0x8 1503 1504 l.slli r4,r4,4 // the amount of info in imediate of jump 1505 l.srli r4,r4,6 // jump instruction with offset 1506 l.sw TRAMP_SLOT_4(r3),r4 // write it to 4th slot 1507 1508 /* fallthrough */ 1509 1510trampoline_out: 1511 // set up new EPC to point to our trampoline code 1512 LOAD_SYMBOL_2_GPR(r5,_immu_trampoline) 1513 l.mtspr r0,r5,SPR_EPCR_BASE 1514 1515 // immu_trampoline is (4x) CACHE_LINE aligned 1516 // and only 6 instructions long, 1517 // so we need to invalidate only 2 lines 1518 1519 /* Establish cache block size 1520 If BS=0, 16; 1521 If BS=1, 32; 1522 r14 contain block size 1523 */ 1524 l.mfspr r21,r0,SPR_ICCFGR 1525 l.andi r21,r21,SPR_ICCFGR_CBS 1526 l.srli r21,r21,7 1527 l.ori r23,r0,16 1528 l.sll r14,r23,r21 1529 1530 l.mtspr r0,r5,SPR_ICBIR 1531 l.add r5,r5,r14 1532 l.mtspr r0,r5,SPR_ICBIR 1533 1534 l.jr r9 1535 l.nop 1536 1537 1538/* 1539 * DSCR: prints a string referenced by r3. 1540 * 1541 * PRMS: r3 - address of the first character of null 1542 * terminated string to be printed 1543 * 1544 * PREQ: UART at UART_BASE_ADD has to be initialized 1545 * 1546 * POST: caller should be aware that r3, r9 are changed 1547 */ 1548ENTRY(_emergency_print) 1549 EMERGENCY_PRINT_STORE_GPR4 1550 EMERGENCY_PRINT_STORE_GPR5 1551 EMERGENCY_PRINT_STORE_GPR6 1552 EMERGENCY_PRINT_STORE_GPR7 15532: 1554 l.lbz r7,0(r3) 1555 l.sfeq r7,r0 1556 l.bf 9f 1557 l.nop 1558 1559// putc: 1560 l.movhi r4,hi(UART_BASE_ADD) 1561 1562 l.addi r6,r0,0x20 15631: l.lbz r5,5(r4) 1564 l.andi r5,r5,0x20 1565 l.sfeq r5,r6 1566 l.bnf 1b 1567 l.nop 1568 1569 l.sb 0(r4),r7 1570 1571 l.addi r6,r0,0x60 15721: l.lbz r5,5(r4) 1573 l.andi r5,r5,0x60 1574 l.sfeq r5,r6 1575 l.bnf 1b 1576 l.nop 1577 1578 /* next character */ 1579 l.j 2b 1580 l.addi r3,r3,0x1 1581 15829: 1583 EMERGENCY_PRINT_LOAD_GPR7 1584 EMERGENCY_PRINT_LOAD_GPR6 1585 EMERGENCY_PRINT_LOAD_GPR5 1586 EMERGENCY_PRINT_LOAD_GPR4 1587 l.jr r9 1588 l.nop 1589 1590ENTRY(_emergency_print_nr) 1591 EMERGENCY_PRINT_STORE_GPR4 1592 EMERGENCY_PRINT_STORE_GPR5 1593 EMERGENCY_PRINT_STORE_GPR6 1594 EMERGENCY_PRINT_STORE_GPR7 1595 EMERGENCY_PRINT_STORE_GPR8 1596 1597 l.addi r8,r0,32 // shift register 1598 15991: /* remove leading zeros */ 1600 l.addi r8,r8,-0x4 1601 l.srl r7,r3,r8 1602 l.andi r7,r7,0xf 1603 1604 /* don't skip the last zero if number == 0x0 */ 1605 l.sfeqi r8,0x4 1606 l.bf 2f 1607 l.nop 1608 1609 l.sfeq r7,r0 1610 l.bf 1b 1611 l.nop 1612 16132: 1614 l.srl r7,r3,r8 1615 1616 l.andi r7,r7,0xf 1617 l.sflts r8,r0 1618 l.bf 9f 1619 1620 l.sfgtui r7,0x9 1621 l.bnf 8f 1622 l.nop 1623 l.addi r7,r7,0x27 1624 16258: 1626 l.addi r7,r7,0x30 1627// putc: 1628 l.movhi r4,hi(UART_BASE_ADD) 1629 1630 l.addi r6,r0,0x20 16311: l.lbz r5,5(r4) 1632 l.andi r5,r5,0x20 1633 l.sfeq r5,r6 1634 l.bnf 1b 1635 l.nop 1636 1637 l.sb 0(r4),r7 1638 1639 l.addi r6,r0,0x60 16401: l.lbz r5,5(r4) 1641 l.andi r5,r5,0x60 1642 l.sfeq r5,r6 1643 l.bnf 1b 1644 l.nop 1645 1646 /* next character */ 1647 l.j 2b 1648 l.addi r8,r8,-0x4 1649 16509: 1651 EMERGENCY_PRINT_LOAD_GPR8 1652 EMERGENCY_PRINT_LOAD_GPR7 1653 EMERGENCY_PRINT_LOAD_GPR6 1654 EMERGENCY_PRINT_LOAD_GPR5 1655 EMERGENCY_PRINT_LOAD_GPR4 1656 l.jr r9 1657 l.nop 1658 1659 1660/* 1661 * This should be used for debugging only. 1662 * It messes up the Linux early serial output 1663 * somehow, so use it sparingly and essentially 1664 * only if you need to debug something that goes wrong 1665 * before Linux gets the early serial going. 1666 * 1667 * Furthermore, you'll have to make sure you set the 1668 * UART_DEVISOR correctly according to the system 1669 * clock rate. 1670 * 1671 * 1672 */ 1673 1674 1675 1676#define SYS_CLK 20000000 1677//#define SYS_CLK 1843200 1678#define OR32_CONSOLE_BAUD 115200 1679#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD) 1680 1681ENTRY(_early_uart_init) 1682 l.movhi r3,hi(UART_BASE_ADD) 1683 1684 l.addi r4,r0,0x7 1685 l.sb 0x2(r3),r4 1686 1687 l.addi r4,r0,0x0 1688 l.sb 0x1(r3),r4 1689 1690 l.addi r4,r0,0x3 1691 l.sb 0x3(r3),r4 1692 1693 l.lbz r5,3(r3) 1694 l.ori r4,r5,0x80 1695 l.sb 0x3(r3),r4 1696 l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff) 1697 l.sb UART_DLM(r3),r4 1698 l.addi r4,r0,((UART_DIVISOR) & 0x000000ff) 1699 l.sb UART_DLL(r3),r4 1700 l.sb 0x3(r3),r5 1701 1702 l.jr r9 1703 l.nop 1704 1705 .align 0x1000 1706 .global _secondary_evbar 1707_secondary_evbar: 1708 1709 .space 0x800 1710 /* Just disable interrupts and Return */ 1711 l.ori r3,r0,SPR_SR_SM 1712 l.mtspr r0,r3,SPR_ESR_BASE 1713 l.rfe 1714 1715 1716 .section .rodata 1717_string_unhandled_exception: 1718 .string "\n\rRunarunaround: Unhandled exception 0x\0" 1719 1720_string_epc_prefix: 1721 .string ": EPC=0x\0" 1722 1723_string_nl: 1724 .string "\n\r\0" 1725 1726 1727/* ========================================[ page aligned structures ]=== */ 1728 1729/* 1730 * .data section should be page aligned 1731 * (look into arch/or32/kernel/vmlinux.lds) 1732 */ 1733 .section .data,"aw" 1734 .align 8192 1735 .global empty_zero_page 1736empty_zero_page: 1737 .space 8192 1738 1739 .global swapper_pg_dir 1740swapper_pg_dir: 1741 .space 8192 1742 1743 .global _unhandled_stack 1744_unhandled_stack: 1745 .space 8192 1746_unhandled_stack_top: 1747 1748/* ============================================================[ EOF ]=== */ 1749