head.S (40590B)
1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * OpenRISC head.S 4 * 5 * Linux architectural port borrowing liberally from similar works of 6 * others. All original copyrights apply as per the original source 7 * declaration. 8 * 9 * Modifications for the OpenRISC architecture: 10 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 11 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 12 */ 13 14#include <linux/linkage.h> 15#include <linux/threads.h> 16#include <linux/errno.h> 17#include <linux/init.h> 18#include <linux/serial_reg.h> 19#include <linux/pgtable.h> 20#include <asm/processor.h> 21#include <asm/page.h> 22#include <asm/mmu.h> 23#include <asm/thread_info.h> 24#include <asm/cache.h> 25#include <asm/spr_defs.h> 26#include <asm/asm-offsets.h> 27#include <linux/of_fdt.h> 28 29#define tophys(rd,rs) \ 30 l.movhi rd,hi(-KERNELBASE) ;\ 31 l.add rd,rd,rs 32 33#define CLEAR_GPR(gpr) \ 34 l.movhi gpr,0x0 35 36#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ 37 l.movhi gpr,hi(symbol) ;\ 38 l.ori gpr,gpr,lo(symbol) 39 40 41#define UART_BASE_ADD 0x90000000 42 43#define EXCEPTION_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_SM) 44#define SYSCALL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_IEE | SPR_SR_TEE | SPR_SR_SM) 45 46/* ============================================[ tmp store locations ]=== */ 47 48#define SPR_SHADOW_GPR(x) ((x) + SPR_GPR_BASE + 32) 49 50/* 51 * emergency_print temporary stores 52 */ 53#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 54#define EMERGENCY_PRINT_STORE_GPR4 l.mtspr r0,r4,SPR_SHADOW_GPR(14) 55#define EMERGENCY_PRINT_LOAD_GPR4 l.mfspr r4,r0,SPR_SHADOW_GPR(14) 56 57#define EMERGENCY_PRINT_STORE_GPR5 l.mtspr r0,r5,SPR_SHADOW_GPR(15) 58#define EMERGENCY_PRINT_LOAD_GPR5 l.mfspr r5,r0,SPR_SHADOW_GPR(15) 59 60#define EMERGENCY_PRINT_STORE_GPR6 l.mtspr r0,r6,SPR_SHADOW_GPR(16) 61#define EMERGENCY_PRINT_LOAD_GPR6 l.mfspr r6,r0,SPR_SHADOW_GPR(16) 62 63#define EMERGENCY_PRINT_STORE_GPR7 l.mtspr r0,r7,SPR_SHADOW_GPR(7) 64#define EMERGENCY_PRINT_LOAD_GPR7 l.mfspr r7,r0,SPR_SHADOW_GPR(7) 65 66#define EMERGENCY_PRINT_STORE_GPR8 l.mtspr r0,r8,SPR_SHADOW_GPR(8) 67#define EMERGENCY_PRINT_LOAD_GPR8 l.mfspr r8,r0,SPR_SHADOW_GPR(8) 68 69#define EMERGENCY_PRINT_STORE_GPR9 l.mtspr r0,r9,SPR_SHADOW_GPR(9) 70#define EMERGENCY_PRINT_LOAD_GPR9 l.mfspr r9,r0,SPR_SHADOW_GPR(9) 71 72#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 73#define EMERGENCY_PRINT_STORE_GPR4 l.sw 0x20(r0),r4 74#define EMERGENCY_PRINT_LOAD_GPR4 l.lwz r4,0x20(r0) 75 76#define EMERGENCY_PRINT_STORE_GPR5 l.sw 0x24(r0),r5 77#define EMERGENCY_PRINT_LOAD_GPR5 l.lwz r5,0x24(r0) 78 79#define EMERGENCY_PRINT_STORE_GPR6 l.sw 0x28(r0),r6 80#define EMERGENCY_PRINT_LOAD_GPR6 l.lwz r6,0x28(r0) 81 82#define EMERGENCY_PRINT_STORE_GPR7 l.sw 0x2c(r0),r7 83#define EMERGENCY_PRINT_LOAD_GPR7 l.lwz r7,0x2c(r0) 84 85#define EMERGENCY_PRINT_STORE_GPR8 l.sw 0x30(r0),r8 86#define EMERGENCY_PRINT_LOAD_GPR8 l.lwz r8,0x30(r0) 87 88#define EMERGENCY_PRINT_STORE_GPR9 l.sw 0x34(r0),r9 89#define EMERGENCY_PRINT_LOAD_GPR9 l.lwz r9,0x34(r0) 90 91#endif 92 93/* 94 * TLB miss handlers temorary stores 95 */ 96#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 97#define EXCEPTION_STORE_GPR2 l.mtspr r0,r2,SPR_SHADOW_GPR(2) 98#define EXCEPTION_LOAD_GPR2 l.mfspr r2,r0,SPR_SHADOW_GPR(2) 99 100#define EXCEPTION_STORE_GPR3 l.mtspr r0,r3,SPR_SHADOW_GPR(3) 101#define EXCEPTION_LOAD_GPR3 l.mfspr r3,r0,SPR_SHADOW_GPR(3) 102 103#define EXCEPTION_STORE_GPR4 l.mtspr r0,r4,SPR_SHADOW_GPR(4) 104#define EXCEPTION_LOAD_GPR4 l.mfspr r4,r0,SPR_SHADOW_GPR(4) 105 106#define EXCEPTION_STORE_GPR5 l.mtspr r0,r5,SPR_SHADOW_GPR(5) 107#define EXCEPTION_LOAD_GPR5 l.mfspr r5,r0,SPR_SHADOW_GPR(5) 108 109#define EXCEPTION_STORE_GPR6 l.mtspr r0,r6,SPR_SHADOW_GPR(6) 110#define EXCEPTION_LOAD_GPR6 l.mfspr r6,r0,SPR_SHADOW_GPR(6) 111 112#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 113#define EXCEPTION_STORE_GPR2 l.sw 0x64(r0),r2 114#define EXCEPTION_LOAD_GPR2 l.lwz r2,0x64(r0) 115 116#define EXCEPTION_STORE_GPR3 l.sw 0x68(r0),r3 117#define EXCEPTION_LOAD_GPR3 l.lwz r3,0x68(r0) 118 119#define EXCEPTION_STORE_GPR4 l.sw 0x6c(r0),r4 120#define EXCEPTION_LOAD_GPR4 l.lwz r4,0x6c(r0) 121 122#define EXCEPTION_STORE_GPR5 l.sw 0x70(r0),r5 123#define EXCEPTION_LOAD_GPR5 l.lwz r5,0x70(r0) 124 125#define EXCEPTION_STORE_GPR6 l.sw 0x74(r0),r6 126#define EXCEPTION_LOAD_GPR6 l.lwz r6,0x74(r0) 127 128#endif 129 130/* 131 * EXCEPTION_HANDLE temporary stores 132 */ 133 134#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS 135#define EXCEPTION_T_STORE_GPR30 l.mtspr r0,r30,SPR_SHADOW_GPR(30) 136#define EXCEPTION_T_LOAD_GPR30(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(30) 137 138#define EXCEPTION_T_STORE_GPR10 l.mtspr r0,r10,SPR_SHADOW_GPR(10) 139#define EXCEPTION_T_LOAD_GPR10(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(10) 140 141#define EXCEPTION_T_STORE_SP l.mtspr r0,r1,SPR_SHADOW_GPR(1) 142#define EXCEPTION_T_LOAD_SP(reg) l.mfspr reg,r0,SPR_SHADOW_GPR(1) 143 144#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */ 145#define EXCEPTION_T_STORE_GPR30 l.sw 0x78(r0),r30 146#define EXCEPTION_T_LOAD_GPR30(reg) l.lwz reg,0x78(r0) 147 148#define EXCEPTION_T_STORE_GPR10 l.sw 0x7c(r0),r10 149#define EXCEPTION_T_LOAD_GPR10(reg) l.lwz reg,0x7c(r0) 150 151#define EXCEPTION_T_STORE_SP l.sw 0x80(r0),r1 152#define EXCEPTION_T_LOAD_SP(reg) l.lwz reg,0x80(r0) 153#endif 154 155/* =========================================================[ macros ]=== */ 156 157#ifdef CONFIG_SMP 158#define GET_CURRENT_PGD(reg,t1) \ 159 LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\ 160 l.mfspr t1,r0,SPR_COREID ;\ 161 l.slli t1,t1,2 ;\ 162 l.add reg,reg,t1 ;\ 163 tophys (t1,reg) ;\ 164 l.lwz reg,0(t1) 165#else 166#define GET_CURRENT_PGD(reg,t1) \ 167 LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\ 168 tophys (t1,reg) ;\ 169 l.lwz reg,0(t1) 170#endif 171 172/* Load r10 from current_thread_info_set - clobbers r1 and r30 */ 173#ifdef CONFIG_SMP 174#define GET_CURRENT_THREAD_INFO \ 175 LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\ 176 tophys (r30,r1) ;\ 177 l.mfspr r10,r0,SPR_COREID ;\ 178 l.slli r10,r10,2 ;\ 179 l.add r30,r30,r10 ;\ 180 /* r10: current_thread_info */ ;\ 181 l.lwz r10,0(r30) 182#else 183#define GET_CURRENT_THREAD_INFO \ 184 LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\ 185 tophys (r30,r1) ;\ 186 /* r10: current_thread_info */ ;\ 187 l.lwz r10,0(r30) 188#endif 189 190/* 191 * DSCR: this is a common hook for handling exceptions. it will save 192 * the needed registers, set up stack and pointer to current 193 * then jump to the handler while enabling MMU 194 * 195 * PRMS: handler - a function to jump to. it has to save the 196 * remaining registers to kernel stack, call 197 * appropriate arch-independant exception handler 198 * and finaly jump to ret_from_except 199 * 200 * PREQ: unchanged state from the time exception happened 201 * 202 * POST: SAVED the following registers original value 203 * to the new created exception frame pointed to by r1 204 * 205 * r1 - ksp pointing to the new (exception) frame 206 * r4 - EEAR exception EA 207 * r10 - current pointing to current_thread_info struct 208 * r12 - syscall 0, since we didn't come from syscall 209 * r30 - handler address of the handler we'll jump to 210 * 211 * handler has to save remaining registers to the exception 212 * ksp frame *before* tainting them! 213 * 214 * NOTE: this function is not reentrant per se. reentrancy is guaranteed 215 * by processor disabling all exceptions/interrupts when exception 216 * accours. 217 * 218 * OPTM: no need to make it so wasteful to extract ksp when in user mode 219 */ 220 221#define EXCEPTION_HANDLE(handler) \ 222 EXCEPTION_T_STORE_GPR30 ;\ 223 l.mfspr r30,r0,SPR_ESR_BASE ;\ 224 l.andi r30,r30,SPR_SR_SM ;\ 225 l.sfeqi r30,0 ;\ 226 EXCEPTION_T_STORE_GPR10 ;\ 227 l.bnf 2f /* kernel_mode */ ;\ 228 EXCEPTION_T_STORE_SP /* delay slot */ ;\ 2291: /* user_mode: */ ;\ 230 GET_CURRENT_THREAD_INFO ;\ 231 tophys (r30,r10) ;\ 232 l.lwz r1,(TI_KSP)(r30) ;\ 233 /* fall through */ ;\ 2342: /* kernel_mode: */ ;\ 235 /* create new stack frame, save only needed gprs */ ;\ 236 /* r1: KSP, r10: current, r4: EEAR, r31: __pa(KSP) */ ;\ 237 /* r12: temp, syscall indicator */ ;\ 238 l.addi r1,r1,-(INT_FRAME_SIZE) ;\ 239 /* r1 is KSP, r30 is __pa(KSP) */ ;\ 240 tophys (r30,r1) ;\ 241 l.sw PT_GPR12(r30),r12 ;\ 242 /* r4 use for tmp before EA */ ;\ 243 l.mfspr r12,r0,SPR_EPCR_BASE ;\ 244 l.sw PT_PC(r30),r12 ;\ 245 l.mfspr r12,r0,SPR_ESR_BASE ;\ 246 l.sw PT_SR(r30),r12 ;\ 247 /* save r30 */ ;\ 248 EXCEPTION_T_LOAD_GPR30(r12) ;\ 249 l.sw PT_GPR30(r30),r12 ;\ 250 /* save r10 as was prior to exception */ ;\ 251 EXCEPTION_T_LOAD_GPR10(r12) ;\ 252 l.sw PT_GPR10(r30),r12 ;\ 253 /* save PT_SP as was prior to exception */ ;\ 254 EXCEPTION_T_LOAD_SP(r12) ;\ 255 l.sw PT_SP(r30),r12 ;\ 256 /* save exception r4, set r4 = EA */ ;\ 257 l.sw PT_GPR4(r30),r4 ;\ 258 l.mfspr r4,r0,SPR_EEAR_BASE ;\ 259 /* r12 == 1 if we come from syscall */ ;\ 260 CLEAR_GPR(r12) ;\ 261 /* ----- turn on MMU ----- */ ;\ 262 /* Carry DSX into exception SR */ ;\ 263 l.mfspr r30,r0,SPR_SR ;\ 264 l.andi r30,r30,SPR_SR_DSX ;\ 265 l.ori r30,r30,(EXCEPTION_SR) ;\ 266 l.mtspr r0,r30,SPR_ESR_BASE ;\ 267 /* r30: EA address of handler */ ;\ 268 LOAD_SYMBOL_2_GPR(r30,handler) ;\ 269 l.mtspr r0,r30,SPR_EPCR_BASE ;\ 270 l.rfe 271 272/* 273 * this doesn't work 274 * 275 * 276 * #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION 277 * #define UNHANDLED_EXCEPTION(handler) \ 278 * l.ori r3,r0,0x1 ;\ 279 * l.mtspr r0,r3,SPR_SR ;\ 280 * l.movhi r3,hi(0xf0000100) ;\ 281 * l.ori r3,r3,lo(0xf0000100) ;\ 282 * l.jr r3 ;\ 283 * l.nop 1 284 * 285 * #endif 286 */ 287 288/* DSCR: this is the same as EXCEPTION_HANDLE(), we are just 289 * a bit more carefull (if we have a PT_SP or current pointer 290 * corruption) and set them up from 'current_set' 291 * 292 */ 293#define UNHANDLED_EXCEPTION(handler) \ 294 EXCEPTION_T_STORE_GPR30 ;\ 295 EXCEPTION_T_STORE_GPR10 ;\ 296 EXCEPTION_T_STORE_SP ;\ 297 /* temporary store r3, r9 into r1, r10 */ ;\ 298 l.addi r1,r3,0x0 ;\ 299 l.addi r10,r9,0x0 ;\ 300 LOAD_SYMBOL_2_GPR(r9,_string_unhandled_exception) ;\ 301 tophys (r3,r9) ;\ 302 l.jal _emergency_print ;\ 303 l.nop ;\ 304 l.mfspr r3,r0,SPR_NPC ;\ 305 l.jal _emergency_print_nr ;\ 306 l.andi r3,r3,0x1f00 ;\ 307 LOAD_SYMBOL_2_GPR(r9,_string_epc_prefix) ;\ 308 tophys (r3,r9) ;\ 309 l.jal _emergency_print ;\ 310 l.nop ;\ 311 l.jal _emergency_print_nr ;\ 312 l.mfspr r3,r0,SPR_EPCR_BASE ;\ 313 LOAD_SYMBOL_2_GPR(r9,_string_nl) ;\ 314 tophys (r3,r9) ;\ 315 l.jal _emergency_print ;\ 316 l.nop ;\ 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 /* 529 * Start the TTCR as early as possible, so that the RNG can make use of 530 * measurements of boot time from the earliest opportunity. Especially 531 * important is that the TTCR does not return zero by the time we reach 532 * random_init(). 533 */ 534 l.movhi r3,hi(SPR_TTMR_CR) 535 l.mtspr r0,r3,SPR_TTMR 536 537 CLEAR_GPR(r1) 538 CLEAR_GPR(r2) 539 CLEAR_GPR(r3) 540 CLEAR_GPR(r4) 541 CLEAR_GPR(r5) 542 CLEAR_GPR(r6) 543 CLEAR_GPR(r7) 544 CLEAR_GPR(r8) 545 CLEAR_GPR(r9) 546 CLEAR_GPR(r10) 547 CLEAR_GPR(r11) 548 CLEAR_GPR(r12) 549 CLEAR_GPR(r13) 550 CLEAR_GPR(r14) 551 CLEAR_GPR(r15) 552 CLEAR_GPR(r16) 553 CLEAR_GPR(r17) 554 CLEAR_GPR(r18) 555 CLEAR_GPR(r19) 556 CLEAR_GPR(r20) 557 CLEAR_GPR(r21) 558 CLEAR_GPR(r22) 559 CLEAR_GPR(r23) 560 CLEAR_GPR(r24) 561 CLEAR_GPR(r26) 562 CLEAR_GPR(r27) 563 CLEAR_GPR(r28) 564 CLEAR_GPR(r29) 565 CLEAR_GPR(r30) 566 CLEAR_GPR(r31) 567 568#ifdef CONFIG_SMP 569 l.mfspr r26,r0,SPR_COREID 570 l.sfeq r26,r0 571 l.bnf secondary_wait 572 l.nop 573#endif 574 /* 575 * set up initial ksp and current 576 */ 577 /* setup kernel stack */ 578 LOAD_SYMBOL_2_GPR(r1,init_thread_union + THREAD_SIZE) 579 LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current 580 tophys (r31,r10) 581 l.sw TI_KSP(r31), r1 582 583 l.ori r4,r0,0x0 584 585 586 /* 587 * .data contains initialized data, 588 * .bss contains uninitialized data - clear it up 589 */ 590clear_bss: 591 LOAD_SYMBOL_2_GPR(r24, __bss_start) 592 LOAD_SYMBOL_2_GPR(r26, _end) 593 tophys(r28,r24) 594 tophys(r30,r26) 595 CLEAR_GPR(r24) 596 CLEAR_GPR(r26) 5971: 598 l.sw (0)(r28),r0 599 l.sfltu r28,r30 600 l.bf 1b 601 l.addi r28,r28,4 602 603enable_ic: 604 l.jal _ic_enable 605 l.nop 606 607enable_dc: 608 l.jal _dc_enable 609 l.nop 610 611flush_tlb: 612 l.jal _flush_tlb 613 l.nop 614 615/* The MMU needs to be enabled before or1k_early_setup is called */ 616 617enable_mmu: 618 /* 619 * enable dmmu & immu 620 * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0 621 */ 622 l.mfspr r30,r0,SPR_SR 623 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 624 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 625 l.or r30,r30,r28 626 l.mtspr r0,r30,SPR_SR 627 l.nop 628 l.nop 629 l.nop 630 l.nop 631 l.nop 632 l.nop 633 l.nop 634 l.nop 635 l.nop 636 l.nop 637 l.nop 638 l.nop 639 l.nop 640 l.nop 641 l.nop 642 l.nop 643 644 // reset the simulation counters 645 l.nop 5 646 647 /* check fdt header magic word */ 648 l.lwz r3,0(r25) /* load magic from fdt into r3 */ 649 l.movhi r4,hi(OF_DT_HEADER) 650 l.ori r4,r4,lo(OF_DT_HEADER) 651 l.sfeq r3,r4 652 l.bf _fdt_found 653 l.nop 654 /* magic number mismatch, set fdt pointer to null */ 655 l.or r25,r0,r0 656_fdt_found: 657 /* pass fdt pointer to or1k_early_setup in r3 */ 658 l.or r3,r0,r25 659 LOAD_SYMBOL_2_GPR(r24, or1k_early_setup) 660 l.jalr r24 661 l.nop 662 663clear_regs: 664 /* 665 * clear all GPRS to increase determinism 666 */ 667 CLEAR_GPR(r2) 668 CLEAR_GPR(r3) 669 CLEAR_GPR(r4) 670 CLEAR_GPR(r5) 671 CLEAR_GPR(r6) 672 CLEAR_GPR(r7) 673 CLEAR_GPR(r8) 674 CLEAR_GPR(r9) 675 CLEAR_GPR(r11) 676 CLEAR_GPR(r12) 677 CLEAR_GPR(r13) 678 CLEAR_GPR(r14) 679 CLEAR_GPR(r15) 680 CLEAR_GPR(r16) 681 CLEAR_GPR(r17) 682 CLEAR_GPR(r18) 683 CLEAR_GPR(r19) 684 CLEAR_GPR(r20) 685 CLEAR_GPR(r21) 686 CLEAR_GPR(r22) 687 CLEAR_GPR(r23) 688 CLEAR_GPR(r24) 689 CLEAR_GPR(r25) 690 CLEAR_GPR(r26) 691 CLEAR_GPR(r27) 692 CLEAR_GPR(r28) 693 CLEAR_GPR(r29) 694 CLEAR_GPR(r30) 695 CLEAR_GPR(r31) 696 697jump_start_kernel: 698 /* 699 * jump to kernel entry (start_kernel) 700 */ 701 LOAD_SYMBOL_2_GPR(r30, start_kernel) 702 l.jr r30 703 l.nop 704 705_flush_tlb: 706 /* 707 * I N V A L I D A T E T L B e n t r i e s 708 */ 709 LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) 710 LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) 711 l.addi r7,r0,128 /* Maximum number of sets */ 7121: 713 l.mtspr r5,r0,0x0 714 l.mtspr r6,r0,0x0 715 716 l.addi r5,r5,1 717 l.addi r6,r6,1 718 l.sfeq r7,r0 719 l.bnf 1b 720 l.addi r7,r7,-1 721 722 l.jr r9 723 l.nop 724 725#ifdef CONFIG_SMP 726secondary_wait: 727 /* Doze the cpu until we are asked to run */ 728 /* If we dont have power management skip doze */ 729 l.mfspr r25,r0,SPR_UPR 730 l.andi r25,r25,SPR_UPR_PMP 731 l.sfeq r25,r0 732 l.bf secondary_check_release 733 l.nop 734 735 /* Setup special secondary exception handler */ 736 LOAD_SYMBOL_2_GPR(r3, _secondary_evbar) 737 tophys(r25,r3) 738 l.mtspr r0,r25,SPR_EVBAR 739 740 /* Enable Interrupts */ 741 l.mfspr r25,r0,SPR_SR 742 l.ori r25,r25,SPR_SR_IEE 743 l.mtspr r0,r25,SPR_SR 744 745 /* Unmask interrupts interrupts */ 746 l.mfspr r25,r0,SPR_PICMR 747 l.ori r25,r25,0xffff 748 l.mtspr r0,r25,SPR_PICMR 749 750 /* Doze */ 751 l.mfspr r25,r0,SPR_PMR 752 LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME) 753 l.or r25,r25,r3 754 l.mtspr r0,r25,SPR_PMR 755 756 /* Wakeup - Restore exception handler */ 757 l.mtspr r0,r0,SPR_EVBAR 758 759secondary_check_release: 760 /* 761 * Check if we actually got the release signal, if not go-back to 762 * sleep. 763 */ 764 l.mfspr r25,r0,SPR_COREID 765 LOAD_SYMBOL_2_GPR(r3, secondary_release) 766 tophys(r4, r3) 767 l.lwz r3,0(r4) 768 l.sfeq r25,r3 769 l.bnf secondary_wait 770 l.nop 771 /* fall through to secondary_init */ 772 773secondary_init: 774 /* 775 * set up initial ksp and current 776 */ 777 LOAD_SYMBOL_2_GPR(r10, secondary_thread_info) 778 tophys (r30,r10) 779 l.lwz r10,0(r30) 780 l.addi r1,r10,THREAD_SIZE 781 tophys (r30,r10) 782 l.sw TI_KSP(r30),r1 783 784 l.jal _ic_enable 785 l.nop 786 787 l.jal _dc_enable 788 l.nop 789 790 l.jal _flush_tlb 791 l.nop 792 793 /* 794 * enable dmmu & immu 795 */ 796 l.mfspr r30,r0,SPR_SR 797 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 798 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 799 l.or r30,r30,r28 800 /* 801 * This is a bit tricky, we need to switch over from physical addresses 802 * to virtual addresses on the fly. 803 * To do that, we first set up ESR with the IME and DME bits set. 804 * Then EPCR is set to secondary_start and then a l.rfe is issued to 805 * "jump" to that. 806 */ 807 l.mtspr r0,r30,SPR_ESR_BASE 808 LOAD_SYMBOL_2_GPR(r30, secondary_start) 809 l.mtspr r0,r30,SPR_EPCR_BASE 810 l.rfe 811 812secondary_start: 813 LOAD_SYMBOL_2_GPR(r30, secondary_start_kernel) 814 l.jr r30 815 l.nop 816 817#endif 818 819/* ========================================[ cache ]=== */ 820 821 /* alignment here so we don't change memory offsets with 822 * memory controller defined 823 */ 824 .align 0x2000 825 826_ic_enable: 827 /* Check if IC present and skip enabling otherwise */ 828 l.mfspr r24,r0,SPR_UPR 829 l.andi r26,r24,SPR_UPR_ICP 830 l.sfeq r26,r0 831 l.bf 9f 832 l.nop 833 834 /* Disable IC */ 835 l.mfspr r6,r0,SPR_SR 836 l.addi r5,r0,-1 837 l.xori r5,r5,SPR_SR_ICE 838 l.and r5,r6,r5 839 l.mtspr r0,r5,SPR_SR 840 841 /* Establish cache block size 842 If BS=0, 16; 843 If BS=1, 32; 844 r14 contain block size 845 */ 846 l.mfspr r24,r0,SPR_ICCFGR 847 l.andi r26,r24,SPR_ICCFGR_CBS 848 l.srli r28,r26,7 849 l.ori r30,r0,16 850 l.sll r14,r30,r28 851 852 /* Establish number of cache sets 853 r16 contains number of cache sets 854 r28 contains log(# of cache sets) 855 */ 856 l.andi r26,r24,SPR_ICCFGR_NCS 857 l.srli r28,r26,3 858 l.ori r30,r0,1 859 l.sll r16,r30,r28 860 861 /* Invalidate IC */ 862 l.addi r6,r0,0 863 l.sll r5,r14,r28 864// l.mul r5,r14,r16 865// l.trap 1 866// l.addi r5,r0,IC_SIZE 8671: 868 l.mtspr r0,r6,SPR_ICBIR 869 l.sfne r6,r5 870 l.bf 1b 871 l.add r6,r6,r14 872 // l.addi r6,r6,IC_LINE 873 874 /* Enable IC */ 875 l.mfspr r6,r0,SPR_SR 876 l.ori r6,r6,SPR_SR_ICE 877 l.mtspr r0,r6,SPR_SR 878 l.nop 879 l.nop 880 l.nop 881 l.nop 882 l.nop 883 l.nop 884 l.nop 885 l.nop 886 l.nop 887 l.nop 8889: 889 l.jr r9 890 l.nop 891 892_dc_enable: 893 /* Check if DC present and skip enabling otherwise */ 894 l.mfspr r24,r0,SPR_UPR 895 l.andi r26,r24,SPR_UPR_DCP 896 l.sfeq r26,r0 897 l.bf 9f 898 l.nop 899 900 /* Disable DC */ 901 l.mfspr r6,r0,SPR_SR 902 l.addi r5,r0,-1 903 l.xori r5,r5,SPR_SR_DCE 904 l.and r5,r6,r5 905 l.mtspr r0,r5,SPR_SR 906 907 /* Establish cache block size 908 If BS=0, 16; 909 If BS=1, 32; 910 r14 contain block size 911 */ 912 l.mfspr r24,r0,SPR_DCCFGR 913 l.andi r26,r24,SPR_DCCFGR_CBS 914 l.srli r28,r26,7 915 l.ori r30,r0,16 916 l.sll r14,r30,r28 917 918 /* Establish number of cache sets 919 r16 contains number of cache sets 920 r28 contains log(# of cache sets) 921 */ 922 l.andi r26,r24,SPR_DCCFGR_NCS 923 l.srli r28,r26,3 924 l.ori r30,r0,1 925 l.sll r16,r30,r28 926 927 /* Invalidate DC */ 928 l.addi r6,r0,0 929 l.sll r5,r14,r28 9301: 931 l.mtspr r0,r6,SPR_DCBIR 932 l.sfne r6,r5 933 l.bf 1b 934 l.add r6,r6,r14 935 936 /* Enable DC */ 937 l.mfspr r6,r0,SPR_SR 938 l.ori r6,r6,SPR_SR_DCE 939 l.mtspr r0,r6,SPR_SR 9409: 941 l.jr r9 942 l.nop 943 944/* ===============================================[ page table masks ]=== */ 945 946#define DTLB_UP_CONVERT_MASK 0x3fa 947#define ITLB_UP_CONVERT_MASK 0x3a 948 949/* for SMP we'd have (this is a bit subtle, CC must be always set 950 * for SMP, but since we have _PAGE_PRESENT bit always defined 951 * we can just modify the mask) 952 */ 953#define DTLB_SMP_CONVERT_MASK 0x3fb 954#define ITLB_SMP_CONVERT_MASK 0x3b 955 956/* ---[ boot dtlb miss handler ]----------------------------------------- */ 957 958boot_dtlb_miss_handler: 959 960/* mask for DTLB_MR register: - (0) sets V (valid) bit, 961 * - (31-12) sets bits belonging to VPN (31-12) 962 */ 963#define DTLB_MR_MASK 0xfffff001 964 965/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit, 966 * - (4) sets A (access) bit, 967 * - (5) sets D (dirty) bit, 968 * - (8) sets SRE (superuser read) bit 969 * - (9) sets SWE (superuser write) bit 970 * - (31-12) sets bits belonging to VPN (31-12) 971 */ 972#define DTLB_TR_MASK 0xfffff332 973 974/* These are for masking out the VPN/PPN value from the MR/TR registers... 975 * it's not the same as the PFN */ 976#define VPN_MASK 0xfffff000 977#define PPN_MASK 0xfffff000 978 979 980 EXCEPTION_STORE_GPR6 981 982#if 0 983 l.mfspr r6,r0,SPR_ESR_BASE // 984 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 985 l.sfeqi r6,0 // r6 == 0x1 --> SM 986 l.bf exit_with_no_dtranslation // 987 l.nop 988#endif 989 990 /* this could be optimized by moving storing of 991 * non r6 registers here, and jumping r6 restore 992 * if not in supervisor mode 993 */ 994 995 EXCEPTION_STORE_GPR2 996 EXCEPTION_STORE_GPR3 997 EXCEPTION_STORE_GPR4 998 EXCEPTION_STORE_GPR5 999 1000 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1001 1002immediate_translation: 1003 CLEAR_GPR(r6) 1004 1005 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1006 1007 l.mfspr r6, r0, SPR_DMMUCFGR 1008 l.andi r6, r6, SPR_DMMUCFGR_NTS 1009 l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF 1010 l.ori r5, r0, 0x1 1011 l.sll r5, r5, r6 // r5 = number DMMU sets 1012 l.addi r6, r5, -1 // r6 = nsets mask 1013 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1014 1015 l.or r6,r6,r4 // r6 <- r4 1016 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1017 l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000 1018 l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK 1019 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry 1020 l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR 1021 1022 /* set up DTLB with no translation for EA <= 0xbfffffff */ 1023 LOAD_SYMBOL_2_GPR(r6,0xbfffffff) 1024 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA) 1025 l.bf 1f // goto out 1026 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1027 1028 tophys(r3,r4) // r3 <- PA 10291: 1030 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1031 l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000 1032 l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK 1033 l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry 1034 l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR 1035 1036 EXCEPTION_LOAD_GPR6 1037 EXCEPTION_LOAD_GPR5 1038 EXCEPTION_LOAD_GPR4 1039 EXCEPTION_LOAD_GPR3 1040 EXCEPTION_LOAD_GPR2 1041 1042 l.rfe // SR <- ESR, PC <- EPC 1043 1044exit_with_no_dtranslation: 1045 /* EA out of memory or not in supervisor mode */ 1046 EXCEPTION_LOAD_GPR6 1047 EXCEPTION_LOAD_GPR4 1048 l.j _dispatch_bus_fault 1049 1050/* ---[ boot itlb miss handler ]----------------------------------------- */ 1051 1052boot_itlb_miss_handler: 1053 1054/* mask for ITLB_MR register: - sets V (valid) bit, 1055 * - sets bits belonging to VPN (15-12) 1056 */ 1057#define ITLB_MR_MASK 0xfffff001 1058 1059/* mask for ITLB_TR register: - sets A (access) bit, 1060 * - sets SXE (superuser execute) bit 1061 * - sets bits belonging to VPN (15-12) 1062 */ 1063#define ITLB_TR_MASK 0xfffff050 1064 1065/* 1066#define VPN_MASK 0xffffe000 1067#define PPN_MASK 0xffffe000 1068*/ 1069 1070 1071 1072 EXCEPTION_STORE_GPR2 1073 EXCEPTION_STORE_GPR3 1074 EXCEPTION_STORE_GPR4 1075 EXCEPTION_STORE_GPR5 1076 EXCEPTION_STORE_GPR6 1077 1078#if 0 1079 l.mfspr r6,r0,SPR_ESR_BASE // 1080 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 1081 l.sfeqi r6,0 // r6 == 0x1 --> SM 1082 l.bf exit_with_no_itranslation 1083 l.nop 1084#endif 1085 1086 1087 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1088 1089earlyearly: 1090 CLEAR_GPR(r6) 1091 1092 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1093 1094 l.mfspr r6, r0, SPR_IMMUCFGR 1095 l.andi r6, r6, SPR_IMMUCFGR_NTS 1096 l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF 1097 l.ori r5, r0, 0x1 1098 l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR 1099 l.addi r6, r5, -1 // r6 = nsets mask 1100 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1101 1102 l.or r6,r6,r4 // r6 <- r4 1103 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1104 l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000 1105 l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK 1106 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry 1107 l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR 1108 1109 /* 1110 * set up ITLB with no translation for EA <= 0x0fffffff 1111 * 1112 * we need this for head.S mapping (EA = PA). if we move all functions 1113 * which run with mmu enabled into entry.S, we might be able to eliminate this. 1114 * 1115 */ 1116 LOAD_SYMBOL_2_GPR(r6,0x0fffffff) 1117 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA) 1118 l.bf 1f // goto out 1119 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1120 1121 tophys(r3,r4) // r3 <- PA 11221: 1123 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1124 l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000 1125 l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK 1126 l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry 1127 l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR 1128 1129 EXCEPTION_LOAD_GPR6 1130 EXCEPTION_LOAD_GPR5 1131 EXCEPTION_LOAD_GPR4 1132 EXCEPTION_LOAD_GPR3 1133 EXCEPTION_LOAD_GPR2 1134 1135 l.rfe // SR <- ESR, PC <- EPC 1136 1137exit_with_no_itranslation: 1138 EXCEPTION_LOAD_GPR4 1139 EXCEPTION_LOAD_GPR6 1140 l.j _dispatch_bus_fault 1141 l.nop 1142 1143/* ====================================================================== */ 1144/* 1145 * Stuff below here shouldn't go into .head section... maybe this stuff 1146 * can be moved to entry.S ??? 1147 */ 1148 1149/* ==============================================[ DTLB miss handler ]=== */ 1150 1151/* 1152 * Comments: 1153 * Exception handlers are entered with MMU off so the following handler 1154 * needs to use physical addressing 1155 * 1156 */ 1157 1158 .text 1159ENTRY(dtlb_miss_handler) 1160 EXCEPTION_STORE_GPR2 1161 EXCEPTION_STORE_GPR3 1162 EXCEPTION_STORE_GPR4 1163 /* 1164 * get EA of the miss 1165 */ 1166 l.mfspr r2,r0,SPR_EEAR_BASE 1167 /* 1168 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1169 */ 1170 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r4 is temp 1171 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1172 l.slli r4,r4,0x2 // to get address << 2 1173 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1174 /* 1175 * if (pmd_none(*pmd)) 1176 * goto pmd_none: 1177 */ 1178 tophys (r4,r3) 1179 l.lwz r3,0x0(r4) // get *pmd value 1180 l.sfne r3,r0 1181 l.bnf d_pmd_none 1182 l.addi r3,r0,0xffffe000 // PAGE_MASK 1183 1184d_pmd_good: 1185 /* 1186 * pte = *pte_offset(pmd, daddr); 1187 */ 1188 l.lwz r4,0x0(r4) // get **pmd value 1189 l.and r4,r4,r3 // & PAGE_MASK 1190 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1191 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1192 l.slli r3,r3,0x2 // to get address << 2 1193 l.add r3,r3,r4 1194 l.lwz r3,0x0(r3) // this is pte at last 1195 /* 1196 * if (!pte_present(pte)) 1197 */ 1198 l.andi r4,r3,0x1 1199 l.sfne r4,r0 // is pte present 1200 l.bnf d_pte_not_present 1201 l.addi r4,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK 1202 /* 1203 * fill DTLB TR register 1204 */ 1205 l.and r4,r3,r4 // apply the mask 1206 // Determine number of DMMU sets 1207 l.mfspr r2, r0, SPR_DMMUCFGR 1208 l.andi r2, r2, SPR_DMMUCFGR_NTS 1209 l.srli r2, r2, SPR_DMMUCFGR_NTS_OFF 1210 l.ori r3, r0, 0x1 1211 l.sll r3, r3, r2 // r3 = number DMMU sets DMMUCFGR 1212 l.addi r2, r3, -1 // r2 = nsets mask 1213 l.mfspr r3, r0, SPR_EEAR_BASE 1214 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1215 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1216 //NUM_TLB_ENTRIES 1217 l.mtspr r2,r4,SPR_DTLBTR_BASE(0) 1218 /* 1219 * fill DTLB MR register 1220 */ 1221 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1222 l.ori r4,r3,0x1 // set hardware valid bit: DTBL_MR entry 1223 l.mtspr r2,r4,SPR_DTLBMR_BASE(0) 1224 1225 EXCEPTION_LOAD_GPR2 1226 EXCEPTION_LOAD_GPR3 1227 EXCEPTION_LOAD_GPR4 1228 l.rfe 1229d_pmd_none: 1230d_pte_not_present: 1231 EXCEPTION_LOAD_GPR2 1232 EXCEPTION_LOAD_GPR3 1233 EXCEPTION_LOAD_GPR4 1234 EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) 1235 1236/* ==============================================[ ITLB miss handler ]=== */ 1237ENTRY(itlb_miss_handler) 1238 EXCEPTION_STORE_GPR2 1239 EXCEPTION_STORE_GPR3 1240 EXCEPTION_STORE_GPR4 1241 /* 1242 * get EA of the miss 1243 */ 1244 l.mfspr r2,r0,SPR_EEAR_BASE 1245 1246 /* 1247 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1248 * 1249 */ 1250 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r5 is temp 1251 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1252 l.slli r4,r4,0x2 // to get address << 2 1253 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1254 /* 1255 * if (pmd_none(*pmd)) 1256 * goto pmd_none: 1257 */ 1258 tophys (r4,r3) 1259 l.lwz r3,0x0(r4) // get *pmd value 1260 l.sfne r3,r0 1261 l.bnf i_pmd_none 1262 l.addi r3,r0,0xffffe000 // PAGE_MASK 1263 1264i_pmd_good: 1265 /* 1266 * pte = *pte_offset(pmd, iaddr); 1267 * 1268 */ 1269 l.lwz r4,0x0(r4) // get **pmd value 1270 l.and r4,r4,r3 // & PAGE_MASK 1271 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1272 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1273 l.slli r3,r3,0x2 // to get address << 2 1274 l.add r3,r3,r4 1275 l.lwz r3,0x0(r3) // this is pte at last 1276 /* 1277 * if (!pte_present(pte)) 1278 * 1279 */ 1280 l.andi r4,r3,0x1 1281 l.sfne r4,r0 // is pte present 1282 l.bnf i_pte_not_present 1283 l.addi r4,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK 1284 /* 1285 * fill ITLB TR register 1286 */ 1287 l.and r4,r3,r4 // apply the mask 1288 l.andi r3,r3,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE 1289 l.sfeq r3,r0 1290 l.bf itlb_tr_fill //_workaround 1291 // Determine number of IMMU sets 1292 l.mfspr r2, r0, SPR_IMMUCFGR 1293 l.andi r2, r2, SPR_IMMUCFGR_NTS 1294 l.srli r2, r2, SPR_IMMUCFGR_NTS_OFF 1295 l.ori r3, r0, 0x1 1296 l.sll r3, r3, r2 // r3 = number IMMU sets IMMUCFGR 1297 l.addi r2, r3, -1 // r2 = nsets mask 1298 l.mfspr r3, r0, SPR_EEAR_BASE 1299 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1300 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1301 1302/* 1303 * __PHX__ :: fixme 1304 * we should not just blindly set executable flags, 1305 * but it does help with ping. the clean way would be to find out 1306 * (and fix it) why stack doesn't have execution permissions 1307 */ 1308 1309itlb_tr_fill_workaround: 1310 l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) 1311itlb_tr_fill: 1312 l.mtspr r2,r4,SPR_ITLBTR_BASE(0) 1313 /* 1314 * fill DTLB MR register 1315 */ 1316 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1317 l.ori r4,r3,0x1 // set hardware valid bit: ITBL_MR entry 1318 l.mtspr r2,r4,SPR_ITLBMR_BASE(0) 1319 1320 EXCEPTION_LOAD_GPR2 1321 EXCEPTION_LOAD_GPR3 1322 EXCEPTION_LOAD_GPR4 1323 l.rfe 1324 1325i_pmd_none: 1326i_pte_not_present: 1327 EXCEPTION_LOAD_GPR2 1328 EXCEPTION_LOAD_GPR3 1329 EXCEPTION_LOAD_GPR4 1330 EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) 1331 1332/* ==============================================[ boot tlb handlers ]=== */ 1333 1334 1335/* =================================================[ debugging aids ]=== */ 1336 1337/* 1338 * DESC: Prints ASCII character stored in r7 1339 * 1340 * PRMS: r7 - a 32-bit value with an ASCII character in the first byte 1341 * position. 1342 * 1343 * PREQ: The UART at UART_BASE_ADD has to be initialized 1344 * 1345 * POST: internally used but restores: 1346 * r4 - to store UART_BASE_ADD 1347 * r5 - for loading OFF_TXFULL / THRE,TEMT 1348 * r6 - for storing bitmask (SERIAL_8250) 1349 */ 1350ENTRY(_emergency_putc) 1351 EMERGENCY_PRINT_STORE_GPR4 1352 EMERGENCY_PRINT_STORE_GPR5 1353 EMERGENCY_PRINT_STORE_GPR6 1354 1355 l.movhi r4,hi(UART_BASE_ADD) 1356 l.ori r4,r4,lo(UART_BASE_ADD) 1357 1358#if defined(CONFIG_SERIAL_LITEUART) 1359 /* Check OFF_TXFULL status */ 13601: l.lwz r5,4(r4) 1361 l.andi r5,r5,0xff 1362 l.sfnei r5,0 1363 l.bf 1b 1364 l.nop 1365 1366 /* Write character */ 1367 l.andi r7,r7,0xff 1368 l.sw 0(r4),r7 1369#elif defined(CONFIG_SERIAL_8250) 1370 /* Check UART LSR THRE (hold) bit */ 1371 l.addi r6,r0,0x20 13721: l.lbz r5,5(r4) 1373 l.andi r5,r5,0x20 1374 l.sfeq r5,r6 1375 l.bnf 1b 1376 l.nop 1377 1378 /* Write character */ 1379 l.sb 0(r4),r7 1380 1381 /* Check UART LSR THRE|TEMT (hold, empty) bits */ 1382 l.addi r6,r0,0x60 13831: l.lbz r5,5(r4) 1384 l.andi r5,r5,0x60 1385 l.sfeq r5,r6 1386 l.bnf 1b 1387 l.nop 1388#endif 1389 EMERGENCY_PRINT_LOAD_GPR6 1390 EMERGENCY_PRINT_LOAD_GPR5 1391 EMERGENCY_PRINT_LOAD_GPR4 1392 l.jr r9 1393 l.nop 1394 1395/* 1396 * DSCR: prints a string referenced by r3. 1397 * 1398 * PRMS: r3 - address of the first character of null 1399 * terminated string to be printed 1400 * 1401 * PREQ: UART at UART_BASE_ADD has to be initialized 1402 * 1403 * POST: caller should be aware that r3, r9 are changed 1404 */ 1405ENTRY(_emergency_print) 1406 EMERGENCY_PRINT_STORE_GPR7 1407 EMERGENCY_PRINT_STORE_GPR9 1408 1409 /* Load character to r7, check for null terminator */ 14102: l.lbz r7,0(r3) 1411 l.sfeqi r7,0x0 1412 l.bf 9f 1413 l.nop 1414 1415 l.jal _emergency_putc 1416 l.nop 1417 1418 /* next character */ 1419 l.j 2b 1420 l.addi r3,r3,0x1 1421 14229: 1423 EMERGENCY_PRINT_LOAD_GPR9 1424 EMERGENCY_PRINT_LOAD_GPR7 1425 l.jr r9 1426 l.nop 1427 1428/* 1429 * DSCR: prints a number in r3 in hex. 1430 * 1431 * PRMS: r3 - a 32-bit unsigned integer 1432 * 1433 * PREQ: UART at UART_BASE_ADD has to be initialized 1434 * 1435 * POST: caller should be aware that r3, r9 are changed 1436 */ 1437ENTRY(_emergency_print_nr) 1438 EMERGENCY_PRINT_STORE_GPR7 1439 EMERGENCY_PRINT_STORE_GPR8 1440 EMERGENCY_PRINT_STORE_GPR9 1441 1442 l.addi r8,r0,32 // shift register 1443 14441: /* remove leading zeros */ 1445 l.addi r8,r8,-0x4 1446 l.srl r7,r3,r8 1447 l.andi r7,r7,0xf 1448 1449 /* don't skip the last zero if number == 0x0 */ 1450 l.sfeqi r8,0x4 1451 l.bf 2f 1452 l.nop 1453 1454 l.sfeq r7,r0 1455 l.bf 1b 1456 l.nop 1457 14582: 1459 l.srl r7,r3,r8 1460 1461 l.andi r7,r7,0xf 1462 l.sflts r8,r0 1463 l.bf 9f 1464 1465 /* Numbers greater than 9 translate to a-f */ 1466 l.sfgtui r7,0x9 1467 l.bnf 8f 1468 l.nop 1469 l.addi r7,r7,0x27 1470 1471 /* Convert to ascii and output character */ 14728: l.jal _emergency_putc 1473 l.addi r7,r7,0x30 1474 1475 /* next character */ 1476 l.j 2b 1477 l.addi r8,r8,-0x4 1478 14799: 1480 EMERGENCY_PRINT_LOAD_GPR9 1481 EMERGENCY_PRINT_LOAD_GPR8 1482 EMERGENCY_PRINT_LOAD_GPR7 1483 l.jr r9 1484 l.nop 1485 1486/* 1487 * This should be used for debugging only. 1488 * It messes up the Linux early serial output 1489 * somehow, so use it sparingly and essentially 1490 * only if you need to debug something that goes wrong 1491 * before Linux gets the early serial going. 1492 * 1493 * Furthermore, you'll have to make sure you set the 1494 * UART_DEVISOR correctly according to the system 1495 * clock rate. 1496 * 1497 * 1498 */ 1499 1500 1501 1502#define SYS_CLK 20000000 1503//#define SYS_CLK 1843200 1504#define OR32_CONSOLE_BAUD 115200 1505#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD) 1506 1507ENTRY(_early_uart_init) 1508 l.movhi r3,hi(UART_BASE_ADD) 1509 l.ori r3,r3,lo(UART_BASE_ADD) 1510 1511#if defined(CONFIG_SERIAL_8250) 1512 l.addi r4,r0,0x7 1513 l.sb 0x2(r3),r4 1514 1515 l.addi r4,r0,0x0 1516 l.sb 0x1(r3),r4 1517 1518 l.addi r4,r0,0x3 1519 l.sb 0x3(r3),r4 1520 1521 l.lbz r5,3(r3) 1522 l.ori r4,r5,0x80 1523 l.sb 0x3(r3),r4 1524 l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff) 1525 l.sb UART_DLM(r3),r4 1526 l.addi r4,r0,((UART_DIVISOR) & 0x000000ff) 1527 l.sb UART_DLL(r3),r4 1528 l.sb 0x3(r3),r5 1529#endif 1530 1531 l.jr r9 1532 l.nop 1533 1534 .align 0x1000 1535 .global _secondary_evbar 1536_secondary_evbar: 1537 1538 .space 0x800 1539 /* Just disable interrupts and Return */ 1540 l.ori r3,r0,SPR_SR_SM 1541 l.mtspr r0,r3,SPR_ESR_BASE 1542 l.rfe 1543 1544 1545 .section .rodata 1546_string_unhandled_exception: 1547 .string "\r\nRunarunaround: Unhandled exception 0x\0" 1548 1549_string_epc_prefix: 1550 .string ": EPC=0x\0" 1551 1552_string_nl: 1553 .string "\r\n\0" 1554 1555 1556/* ========================================[ page aligned structures ]=== */ 1557 1558/* 1559 * .data section should be page aligned 1560 * (look into arch/openrisc/kernel/vmlinux.lds.S) 1561 */ 1562 .section .data,"aw" 1563 .align 8192 1564 .global empty_zero_page 1565empty_zero_page: 1566 .space 8192 1567 1568 .global swapper_pg_dir 1569swapper_pg_dir: 1570 .space 8192 1571 1572 .global _unhandled_stack 1573_unhandled_stack: 1574 .space 8192 1575_unhandled_stack_top: 1576 1577/* ============================================================[ EOF ]=== */