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 __HEAD 361 362/* ---[ 0x100: RESET exception ]----------------------------------------- */ 363 .org 0x100 364 /* Jump to .init code at _start which lives in the .head section 365 * and will be discarded after boot. 366 */ 367 LOAD_SYMBOL_2_GPR(r15, _start) 368 tophys (r13,r15) /* MMU disabled */ 369 l.jr r13 370 l.nop 371 372/* ---[ 0x200: BUS exception ]------------------------------------------- */ 373 .org 0x200 374_dispatch_bus_fault: 375 EXCEPTION_HANDLE(_bus_fault_handler) 376 377/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ 378 .org 0x300 379_dispatch_do_dpage_fault: 380// totaly disable timer interrupt 381// l.mtspr r0,r0,SPR_TTMR 382// DEBUG_TLB_PROBE(0x300) 383// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x300) 384 EXCEPTION_HANDLE(_data_page_fault_handler) 385 386/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ 387 .org 0x400 388_dispatch_do_ipage_fault: 389// totaly disable timer interrupt 390// l.mtspr r0,r0,SPR_TTMR 391// DEBUG_TLB_PROBE(0x400) 392// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x400) 393 EXCEPTION_HANDLE(_insn_page_fault_handler) 394 395/* ---[ 0x500: Timer exception ]----------------------------------------- */ 396 .org 0x500 397 EXCEPTION_HANDLE(_timer_handler) 398 399/* ---[ 0x600: Alignment exception ]------------------------------------- */ 400 .org 0x600 401 EXCEPTION_HANDLE(_alignment_handler) 402 403/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ 404 .org 0x700 405 EXCEPTION_HANDLE(_illegal_instruction_handler) 406 407/* ---[ 0x800: External interrupt exception ]---------------------------- */ 408 .org 0x800 409 EXCEPTION_HANDLE(_external_irq_handler) 410 411/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ 412 .org 0x900 413 l.j boot_dtlb_miss_handler 414 l.nop 415 416/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ 417 .org 0xa00 418 l.j boot_itlb_miss_handler 419 l.nop 420 421/* ---[ 0xb00: Range exception ]----------------------------------------- */ 422 .org 0xb00 423 UNHANDLED_EXCEPTION(_vector_0xb00) 424 425/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ 426 .org 0xc00 427 EXCEPTION_HANDLE(_sys_call_handler) 428 429/* ---[ 0xd00: Floating point exception ]-------------------------------- */ 430 .org 0xd00 431 EXCEPTION_HANDLE(_fpe_trap_handler) 432 433/* ---[ 0xe00: Trap exception ]------------------------------------------ */ 434 .org 0xe00 435// UNHANDLED_EXCEPTION(_vector_0xe00) 436 EXCEPTION_HANDLE(_trap_handler) 437 438/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ 439 .org 0xf00 440 UNHANDLED_EXCEPTION(_vector_0xf00) 441 442/* ---[ 0x1000: Reserved exception ]------------------------------------- */ 443 .org 0x1000 444 UNHANDLED_EXCEPTION(_vector_0x1000) 445 446/* ---[ 0x1100: Reserved exception ]------------------------------------- */ 447 .org 0x1100 448 UNHANDLED_EXCEPTION(_vector_0x1100) 449 450/* ---[ 0x1200: Reserved exception ]------------------------------------- */ 451 .org 0x1200 452 UNHANDLED_EXCEPTION(_vector_0x1200) 453 454/* ---[ 0x1300: Reserved exception ]------------------------------------- */ 455 .org 0x1300 456 UNHANDLED_EXCEPTION(_vector_0x1300) 457 458/* ---[ 0x1400: Reserved exception ]------------------------------------- */ 459 .org 0x1400 460 UNHANDLED_EXCEPTION(_vector_0x1400) 461 462/* ---[ 0x1500: Reserved exception ]------------------------------------- */ 463 .org 0x1500 464 UNHANDLED_EXCEPTION(_vector_0x1500) 465 466/* ---[ 0x1600: Reserved exception ]------------------------------------- */ 467 .org 0x1600 468 UNHANDLED_EXCEPTION(_vector_0x1600) 469 470/* ---[ 0x1700: Reserved exception ]------------------------------------- */ 471 .org 0x1700 472 UNHANDLED_EXCEPTION(_vector_0x1700) 473 474/* ---[ 0x1800: Reserved exception ]------------------------------------- */ 475 .org 0x1800 476 UNHANDLED_EXCEPTION(_vector_0x1800) 477 478/* ---[ 0x1900: Reserved exception ]------------------------------------- */ 479 .org 0x1900 480 UNHANDLED_EXCEPTION(_vector_0x1900) 481 482/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ 483 .org 0x1a00 484 UNHANDLED_EXCEPTION(_vector_0x1a00) 485 486/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ 487 .org 0x1b00 488 UNHANDLED_EXCEPTION(_vector_0x1b00) 489 490/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ 491 .org 0x1c00 492 UNHANDLED_EXCEPTION(_vector_0x1c00) 493 494/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ 495 .org 0x1d00 496 UNHANDLED_EXCEPTION(_vector_0x1d00) 497 498/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ 499 .org 0x1e00 500 UNHANDLED_EXCEPTION(_vector_0x1e00) 501 502/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ 503 .org 0x1f00 504 UNHANDLED_EXCEPTION(_vector_0x1f00) 505 506 .org 0x2000 507/* ===================================================[ kernel start ]=== */ 508 509/* .text*/ 510 511/* This early stuff belongs in the .init.text section, but some of the functions below definitely 512 * don't... */ 513 514 __INIT 515 .global _start 516_start: 517 /* Init r0 to zero as per spec */ 518 CLEAR_GPR(r0) 519 520 /* save kernel parameters */ 521 l.or r25,r0,r3 /* pointer to fdt */ 522 523 /* 524 * ensure a deterministic start 525 */ 526 527 l.ori r3,r0,0x1 528 l.mtspr r0,r3,SPR_SR 529 530 /* 531 * Start the TTCR as early as possible, so that the RNG can make use of 532 * measurements of boot time from the earliest opportunity. Especially 533 * important is that the TTCR does not return zero by the time we reach 534 * random_init(). 535 */ 536 l.movhi r3,hi(SPR_TTMR_CR) 537 l.mtspr r0,r3,SPR_TTMR 538 539 CLEAR_GPR(r1) 540 CLEAR_GPR(r2) 541 CLEAR_GPR(r3) 542 CLEAR_GPR(r4) 543 CLEAR_GPR(r5) 544 CLEAR_GPR(r6) 545 CLEAR_GPR(r7) 546 CLEAR_GPR(r8) 547 CLEAR_GPR(r9) 548 CLEAR_GPR(r10) 549 CLEAR_GPR(r11) 550 CLEAR_GPR(r12) 551 CLEAR_GPR(r13) 552 CLEAR_GPR(r14) 553 CLEAR_GPR(r15) 554 CLEAR_GPR(r16) 555 CLEAR_GPR(r17) 556 CLEAR_GPR(r18) 557 CLEAR_GPR(r19) 558 CLEAR_GPR(r20) 559 CLEAR_GPR(r21) 560 CLEAR_GPR(r22) 561 CLEAR_GPR(r23) 562 CLEAR_GPR(r24) 563 CLEAR_GPR(r26) 564 CLEAR_GPR(r27) 565 CLEAR_GPR(r28) 566 CLEAR_GPR(r29) 567 CLEAR_GPR(r30) 568 CLEAR_GPR(r31) 569 570#ifdef CONFIG_SMP 571 l.mfspr r26,r0,SPR_COREID 572 l.sfeq r26,r0 573 l.bnf secondary_wait 574 l.nop 575#endif 576 /* 577 * set up initial ksp and current 578 */ 579 /* setup kernel stack */ 580 LOAD_SYMBOL_2_GPR(r1,init_thread_union + THREAD_SIZE) 581 LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current 582 tophys (r31,r10) 583 l.sw TI_KSP(r31), r1 584 585 l.ori r4,r0,0x0 586 587 588 /* 589 * .data contains initialized data, 590 * .bss contains uninitialized data - clear it up 591 */ 592clear_bss: 593 LOAD_SYMBOL_2_GPR(r24, __bss_start) 594 LOAD_SYMBOL_2_GPR(r26, _end) 595 tophys(r28,r24) 596 tophys(r30,r26) 597 CLEAR_GPR(r24) 598 CLEAR_GPR(r26) 5991: 600 l.sw (0)(r28),r0 601 l.sfltu r28,r30 602 l.bf 1b 603 l.addi r28,r28,4 604 605enable_ic: 606 l.jal _ic_enable 607 l.nop 608 609enable_dc: 610 l.jal _dc_enable 611 l.nop 612 613flush_tlb: 614 l.jal _flush_tlb 615 l.nop 616 617/* The MMU needs to be enabled before or1k_early_setup is called */ 618 619enable_mmu: 620 /* 621 * enable dmmu & immu 622 * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0 623 */ 624 l.mfspr r30,r0,SPR_SR 625 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 626 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 627 l.or r30,r30,r28 628 l.mtspr r0,r30,SPR_SR 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 l.nop 644 l.nop 645 646 // reset the simulation counters 647 l.nop 5 648 649 /* check fdt header magic word */ 650 l.lwz r3,0(r25) /* load magic from fdt into r3 */ 651 l.movhi r4,hi(OF_DT_HEADER) 652 l.ori r4,r4,lo(OF_DT_HEADER) 653 l.sfeq r3,r4 654 l.bf _fdt_found 655 l.nop 656 /* magic number mismatch, set fdt pointer to null */ 657 l.or r25,r0,r0 658_fdt_found: 659 /* pass fdt pointer to or1k_early_setup in r3 */ 660 l.or r3,r0,r25 661 LOAD_SYMBOL_2_GPR(r24, or1k_early_setup) 662 l.jalr r24 663 l.nop 664 665clear_regs: 666 /* 667 * clear all GPRS to increase determinism 668 */ 669 CLEAR_GPR(r2) 670 CLEAR_GPR(r3) 671 CLEAR_GPR(r4) 672 CLEAR_GPR(r5) 673 CLEAR_GPR(r6) 674 CLEAR_GPR(r7) 675 CLEAR_GPR(r8) 676 CLEAR_GPR(r9) 677 CLEAR_GPR(r11) 678 CLEAR_GPR(r12) 679 CLEAR_GPR(r13) 680 CLEAR_GPR(r14) 681 CLEAR_GPR(r15) 682 CLEAR_GPR(r16) 683 CLEAR_GPR(r17) 684 CLEAR_GPR(r18) 685 CLEAR_GPR(r19) 686 CLEAR_GPR(r20) 687 CLEAR_GPR(r21) 688 CLEAR_GPR(r22) 689 CLEAR_GPR(r23) 690 CLEAR_GPR(r24) 691 CLEAR_GPR(r25) 692 CLEAR_GPR(r26) 693 CLEAR_GPR(r27) 694 CLEAR_GPR(r28) 695 CLEAR_GPR(r29) 696 CLEAR_GPR(r30) 697 CLEAR_GPR(r31) 698 699jump_start_kernel: 700 /* 701 * jump to kernel entry (start_kernel) 702 */ 703 LOAD_SYMBOL_2_GPR(r30, start_kernel) 704 l.jr r30 705 l.nop 706 707_flush_tlb: 708 /* 709 * I N V A L I D A T E T L B e n t r i e s 710 */ 711 LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) 712 LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) 713 l.addi r7,r0,128 /* Maximum number of sets */ 7141: 715 l.mtspr r5,r0,0x0 716 l.mtspr r6,r0,0x0 717 718 l.addi r5,r5,1 719 l.addi r6,r6,1 720 l.sfeq r7,r0 721 l.bnf 1b 722 l.addi r7,r7,-1 723 724 l.jr r9 725 l.nop 726 727#ifdef CONFIG_SMP 728secondary_wait: 729 /* Doze the cpu until we are asked to run */ 730 /* If we dont have power management skip doze */ 731 l.mfspr r25,r0,SPR_UPR 732 l.andi r25,r25,SPR_UPR_PMP 733 l.sfeq r25,r0 734 l.bf secondary_check_release 735 l.nop 736 737 /* Setup special secondary exception handler */ 738 LOAD_SYMBOL_2_GPR(r3, _secondary_evbar) 739 tophys(r25,r3) 740 l.mtspr r0,r25,SPR_EVBAR 741 742 /* Enable Interrupts */ 743 l.mfspr r25,r0,SPR_SR 744 l.ori r25,r25,SPR_SR_IEE 745 l.mtspr r0,r25,SPR_SR 746 747 /* Unmask interrupts interrupts */ 748 l.mfspr r25,r0,SPR_PICMR 749 l.ori r25,r25,0xffff 750 l.mtspr r0,r25,SPR_PICMR 751 752 /* Doze */ 753 l.mfspr r25,r0,SPR_PMR 754 LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME) 755 l.or r25,r25,r3 756 l.mtspr r0,r25,SPR_PMR 757 758 /* Wakeup - Restore exception handler */ 759 l.mtspr r0,r0,SPR_EVBAR 760 761secondary_check_release: 762 /* 763 * Check if we actually got the release signal, if not go-back to 764 * sleep. 765 */ 766 l.mfspr r25,r0,SPR_COREID 767 LOAD_SYMBOL_2_GPR(r3, secondary_release) 768 tophys(r4, r3) 769 l.lwz r3,0(r4) 770 l.sfeq r25,r3 771 l.bnf secondary_wait 772 l.nop 773 /* fall through to secondary_init */ 774 775secondary_init: 776 /* 777 * set up initial ksp and current 778 */ 779 LOAD_SYMBOL_2_GPR(r10, secondary_thread_info) 780 tophys (r30,r10) 781 l.lwz r10,0(r30) 782 l.addi r1,r10,THREAD_SIZE 783 tophys (r30,r10) 784 l.sw TI_KSP(r30),r1 785 786 l.jal _ic_enable 787 l.nop 788 789 l.jal _dc_enable 790 l.nop 791 792 l.jal _flush_tlb 793 l.nop 794 795 /* 796 * enable dmmu & immu 797 */ 798 l.mfspr r30,r0,SPR_SR 799 l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME) 800 l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME) 801 l.or r30,r30,r28 802 /* 803 * This is a bit tricky, we need to switch over from physical addresses 804 * to virtual addresses on the fly. 805 * To do that, we first set up ESR with the IME and DME bits set. 806 * Then EPCR is set to secondary_start and then a l.rfe is issued to 807 * "jump" to that. 808 */ 809 l.mtspr r0,r30,SPR_ESR_BASE 810 LOAD_SYMBOL_2_GPR(r30, secondary_start) 811 l.mtspr r0,r30,SPR_EPCR_BASE 812 l.rfe 813 814secondary_start: 815 LOAD_SYMBOL_2_GPR(r30, secondary_start_kernel) 816 l.jr r30 817 l.nop 818 819#endif 820 821/* ==========================================================[ cache ]=== */ 822 823 /* alignment here so we don't change memory offsets with 824 * memory controller defined 825 */ 826 .align 0x2000 827 828_ic_enable: 829 /* Check if IC present and skip enabling otherwise */ 830 l.mfspr r24,r0,SPR_UPR 831 l.andi r26,r24,SPR_UPR_ICP 832 l.sfeq r26,r0 833 l.bf 9f 834 l.nop 835 836 /* Disable IC */ 837 l.mfspr r6,r0,SPR_SR 838 l.addi r5,r0,-1 839 l.xori r5,r5,SPR_SR_ICE 840 l.and r5,r6,r5 841 l.mtspr r0,r5,SPR_SR 842 843 /* Establish cache block size 844 If BS=0, 16; 845 If BS=1, 32; 846 r14 contain block size 847 */ 848 l.mfspr r24,r0,SPR_ICCFGR 849 l.andi r26,r24,SPR_ICCFGR_CBS 850 l.srli r28,r26,7 851 l.ori r30,r0,16 852 l.sll r14,r30,r28 853 854 /* Establish number of cache sets 855 r16 contains number of cache sets 856 r28 contains log(# of cache sets) 857 */ 858 l.andi r26,r24,SPR_ICCFGR_NCS 859 l.srli r28,r26,3 860 l.ori r30,r0,1 861 l.sll r16,r30,r28 862 863 /* Invalidate IC */ 864 l.addi r6,r0,0 865 l.sll r5,r14,r28 866// l.mul r5,r14,r16 867// l.trap 1 868// l.addi r5,r0,IC_SIZE 8691: 870 l.mtspr r0,r6,SPR_ICBIR 871 l.sfne r6,r5 872 l.bf 1b 873 l.add r6,r6,r14 874 // l.addi r6,r6,IC_LINE 875 876 /* Enable IC */ 877 l.mfspr r6,r0,SPR_SR 878 l.ori r6,r6,SPR_SR_ICE 879 l.mtspr r0,r6,SPR_SR 880 l.nop 881 l.nop 882 l.nop 883 l.nop 884 l.nop 885 l.nop 886 l.nop 887 l.nop 888 l.nop 889 l.nop 8909: 891 l.jr r9 892 l.nop 893 894_dc_enable: 895 /* Check if DC present and skip enabling otherwise */ 896 l.mfspr r24,r0,SPR_UPR 897 l.andi r26,r24,SPR_UPR_DCP 898 l.sfeq r26,r0 899 l.bf 9f 900 l.nop 901 902 /* Disable DC */ 903 l.mfspr r6,r0,SPR_SR 904 l.addi r5,r0,-1 905 l.xori r5,r5,SPR_SR_DCE 906 l.and r5,r6,r5 907 l.mtspr r0,r5,SPR_SR 908 909 /* Establish cache block size 910 If BS=0, 16; 911 If BS=1, 32; 912 r14 contain block size 913 */ 914 l.mfspr r24,r0,SPR_DCCFGR 915 l.andi r26,r24,SPR_DCCFGR_CBS 916 l.srli r28,r26,7 917 l.ori r30,r0,16 918 l.sll r14,r30,r28 919 920 /* Establish number of cache sets 921 r16 contains number of cache sets 922 r28 contains log(# of cache sets) 923 */ 924 l.andi r26,r24,SPR_DCCFGR_NCS 925 l.srli r28,r26,3 926 l.ori r30,r0,1 927 l.sll r16,r30,r28 928 929 /* Invalidate DC */ 930 l.addi r6,r0,0 931 l.sll r5,r14,r28 9321: 933 l.mtspr r0,r6,SPR_DCBIR 934 l.sfne r6,r5 935 l.bf 1b 936 l.add r6,r6,r14 937 938 /* Enable DC */ 939 l.mfspr r6,r0,SPR_SR 940 l.ori r6,r6,SPR_SR_DCE 941 l.mtspr r0,r6,SPR_SR 9429: 943 l.jr r9 944 l.nop 945 946/* ===============================================[ page table masks ]=== */ 947 948#define DTLB_UP_CONVERT_MASK 0x3fa 949#define ITLB_UP_CONVERT_MASK 0x3a 950 951/* for SMP we'd have (this is a bit subtle, CC must be always set 952 * for SMP, but since we have _PAGE_PRESENT bit always defined 953 * we can just modify the mask) 954 */ 955#define DTLB_SMP_CONVERT_MASK 0x3fb 956#define ITLB_SMP_CONVERT_MASK 0x3b 957 958/* ---[ boot dtlb miss handler ]----------------------------------------- */ 959 960boot_dtlb_miss_handler: 961 962/* mask for DTLB_MR register: - (0) sets V (valid) bit, 963 * - (31-12) sets bits belonging to VPN (31-12) 964 */ 965#define DTLB_MR_MASK 0xfffff001 966 967/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit, 968 * - (4) sets A (access) bit, 969 * - (5) sets D (dirty) bit, 970 * - (8) sets SRE (superuser read) bit 971 * - (9) sets SWE (superuser write) bit 972 * - (31-12) sets bits belonging to VPN (31-12) 973 */ 974#define DTLB_TR_MASK 0xfffff332 975 976/* These are for masking out the VPN/PPN value from the MR/TR registers... 977 * it's not the same as the PFN */ 978#define VPN_MASK 0xfffff000 979#define PPN_MASK 0xfffff000 980 981 982 EXCEPTION_STORE_GPR6 983 984#if 0 985 l.mfspr r6,r0,SPR_ESR_BASE // 986 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 987 l.sfeqi r6,0 // r6 == 0x1 --> SM 988 l.bf exit_with_no_dtranslation // 989 l.nop 990#endif 991 992 /* this could be optimized by moving storing of 993 * non r6 registers here, and jumping r6 restore 994 * if not in supervisor mode 995 */ 996 997 EXCEPTION_STORE_GPR2 998 EXCEPTION_STORE_GPR3 999 EXCEPTION_STORE_GPR4 1000 EXCEPTION_STORE_GPR5 1001 1002 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1003 1004immediate_translation: 1005 CLEAR_GPR(r6) 1006 1007 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1008 1009 l.mfspr r6, r0, SPR_DMMUCFGR 1010 l.andi r6, r6, SPR_DMMUCFGR_NTS 1011 l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF 1012 l.ori r5, r0, 0x1 1013 l.sll r5, r5, r6 // r5 = number DMMU sets 1014 l.addi r6, r5, -1 // r6 = nsets mask 1015 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1016 1017 l.or r6,r6,r4 // r6 <- r4 1018 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1019 l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000 1020 l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK 1021 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry 1022 l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR 1023 1024 /* set up DTLB with no translation for EA <= 0xbfffffff */ 1025 LOAD_SYMBOL_2_GPR(r6,0xbfffffff) 1026 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA) 1027 l.bf 1f // goto out 1028 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1029 1030 tophys(r3,r4) // r3 <- PA 10311: 1032 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1033 l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000 1034 l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK 1035 l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry 1036 l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR 1037 1038 EXCEPTION_LOAD_GPR6 1039 EXCEPTION_LOAD_GPR5 1040 EXCEPTION_LOAD_GPR4 1041 EXCEPTION_LOAD_GPR3 1042 EXCEPTION_LOAD_GPR2 1043 1044 l.rfe // SR <- ESR, PC <- EPC 1045 1046exit_with_no_dtranslation: 1047 /* EA out of memory or not in supervisor mode */ 1048 EXCEPTION_LOAD_GPR6 1049 EXCEPTION_LOAD_GPR4 1050 l.j _dispatch_bus_fault 1051 1052/* ---[ boot itlb miss handler ]----------------------------------------- */ 1053 1054boot_itlb_miss_handler: 1055 1056/* mask for ITLB_MR register: - sets V (valid) bit, 1057 * - sets bits belonging to VPN (15-12) 1058 */ 1059#define ITLB_MR_MASK 0xfffff001 1060 1061/* mask for ITLB_TR register: - sets A (access) bit, 1062 * - sets SXE (superuser execute) bit 1063 * - sets bits belonging to VPN (15-12) 1064 */ 1065#define ITLB_TR_MASK 0xfffff050 1066 1067/* 1068#define VPN_MASK 0xffffe000 1069#define PPN_MASK 0xffffe000 1070*/ 1071 1072 1073 1074 EXCEPTION_STORE_GPR2 1075 EXCEPTION_STORE_GPR3 1076 EXCEPTION_STORE_GPR4 1077 EXCEPTION_STORE_GPR5 1078 EXCEPTION_STORE_GPR6 1079 1080#if 0 1081 l.mfspr r6,r0,SPR_ESR_BASE // 1082 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 1083 l.sfeqi r6,0 // r6 == 0x1 --> SM 1084 l.bf exit_with_no_itranslation 1085 l.nop 1086#endif 1087 1088 1089 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1090 1091earlyearly: 1092 CLEAR_GPR(r6) 1093 1094 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1095 1096 l.mfspr r6, r0, SPR_IMMUCFGR 1097 l.andi r6, r6, SPR_IMMUCFGR_NTS 1098 l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF 1099 l.ori r5, r0, 0x1 1100 l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR 1101 l.addi r6, r5, -1 // r6 = nsets mask 1102 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1103 1104 l.or r6,r6,r4 // r6 <- r4 1105 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1106 l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000 1107 l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK 1108 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry 1109 l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR 1110 1111 /* 1112 * set up ITLB with no translation for EA <= 0x0fffffff 1113 * 1114 * we need this for head.S mapping (EA = PA). if we move all functions 1115 * which run with mmu enabled into entry.S, we might be able to eliminate this. 1116 * 1117 */ 1118 LOAD_SYMBOL_2_GPR(r6,0x0fffffff) 1119 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA) 1120 l.bf 1f // goto out 1121 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1122 1123 tophys(r3,r4) // r3 <- PA 11241: 1125 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1126 l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000 1127 l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK 1128 l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry 1129 l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR 1130 1131 EXCEPTION_LOAD_GPR6 1132 EXCEPTION_LOAD_GPR5 1133 EXCEPTION_LOAD_GPR4 1134 EXCEPTION_LOAD_GPR3 1135 EXCEPTION_LOAD_GPR2 1136 1137 l.rfe // SR <- ESR, PC <- EPC 1138 1139exit_with_no_itranslation: 1140 EXCEPTION_LOAD_GPR4 1141 EXCEPTION_LOAD_GPR6 1142 l.j _dispatch_bus_fault 1143 l.nop 1144 1145/* ====================================================================== */ 1146/* 1147 * Stuff below here shouldn't go into .head section... maybe this stuff 1148 * can be moved to entry.S ??? 1149 */ 1150 1151/* ==============================================[ DTLB miss handler ]=== */ 1152 1153/* 1154 * Comments: 1155 * Exception handlers are entered with MMU off so the following handler 1156 * needs to use physical addressing 1157 * 1158 */ 1159 1160 .text 1161ENTRY(dtlb_miss_handler) 1162 EXCEPTION_STORE_GPR2 1163 EXCEPTION_STORE_GPR3 1164 EXCEPTION_STORE_GPR4 1165 /* 1166 * get EA of the miss 1167 */ 1168 l.mfspr r2,r0,SPR_EEAR_BASE 1169 /* 1170 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1171 */ 1172 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r4 is temp 1173 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1174 l.slli r4,r4,0x2 // to get address << 2 1175 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1176 /* 1177 * if (pmd_none(*pmd)) 1178 * goto pmd_none: 1179 */ 1180 tophys (r4,r3) 1181 l.lwz r3,0x0(r4) // get *pmd value 1182 l.sfne r3,r0 1183 l.bnf d_pmd_none 1184 l.addi r3,r0,0xffffe000 // PAGE_MASK 1185 1186d_pmd_good: 1187 /* 1188 * pte = *pte_offset(pmd, daddr); 1189 */ 1190 l.lwz r4,0x0(r4) // get **pmd value 1191 l.and r4,r4,r3 // & PAGE_MASK 1192 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1193 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1194 l.slli r3,r3,0x2 // to get address << 2 1195 l.add r3,r3,r4 1196 l.lwz r3,0x0(r3) // this is pte at last 1197 /* 1198 * if (!pte_present(pte)) 1199 */ 1200 l.andi r4,r3,0x1 1201 l.sfne r4,r0 // is pte present 1202 l.bnf d_pte_not_present 1203 l.addi r4,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK 1204 /* 1205 * fill DTLB TR register 1206 */ 1207 l.and r4,r3,r4 // apply the mask 1208 // Determine number of DMMU sets 1209 l.mfspr r2, r0, SPR_DMMUCFGR 1210 l.andi r2, r2, SPR_DMMUCFGR_NTS 1211 l.srli r2, r2, SPR_DMMUCFGR_NTS_OFF 1212 l.ori r3, r0, 0x1 1213 l.sll r3, r3, r2 // r3 = number DMMU sets DMMUCFGR 1214 l.addi r2, r3, -1 // r2 = nsets mask 1215 l.mfspr r3, r0, SPR_EEAR_BASE 1216 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1217 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1218 //NUM_TLB_ENTRIES 1219 l.mtspr r2,r4,SPR_DTLBTR_BASE(0) 1220 /* 1221 * fill DTLB MR register 1222 */ 1223 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1224 l.ori r4,r3,0x1 // set hardware valid bit: DTBL_MR entry 1225 l.mtspr r2,r4,SPR_DTLBMR_BASE(0) 1226 1227 EXCEPTION_LOAD_GPR2 1228 EXCEPTION_LOAD_GPR3 1229 EXCEPTION_LOAD_GPR4 1230 l.rfe 1231d_pmd_none: 1232d_pte_not_present: 1233 EXCEPTION_LOAD_GPR2 1234 EXCEPTION_LOAD_GPR3 1235 EXCEPTION_LOAD_GPR4 1236 EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) 1237 1238/* ==============================================[ ITLB miss handler ]=== */ 1239ENTRY(itlb_miss_handler) 1240 EXCEPTION_STORE_GPR2 1241 EXCEPTION_STORE_GPR3 1242 EXCEPTION_STORE_GPR4 1243 /* 1244 * get EA of the miss 1245 */ 1246 l.mfspr r2,r0,SPR_EEAR_BASE 1247 1248 /* 1249 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1250 * 1251 */ 1252 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r5 is temp 1253 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1254 l.slli r4,r4,0x2 // to get address << 2 1255 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1256 /* 1257 * if (pmd_none(*pmd)) 1258 * goto pmd_none: 1259 */ 1260 tophys (r4,r3) 1261 l.lwz r3,0x0(r4) // get *pmd value 1262 l.sfne r3,r0 1263 l.bnf i_pmd_none 1264 l.addi r3,r0,0xffffe000 // PAGE_MASK 1265 1266i_pmd_good: 1267 /* 1268 * pte = *pte_offset(pmd, iaddr); 1269 * 1270 */ 1271 l.lwz r4,0x0(r4) // get **pmd value 1272 l.and r4,r4,r3 // & PAGE_MASK 1273 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1274 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1275 l.slli r3,r3,0x2 // to get address << 2 1276 l.add r3,r3,r4 1277 l.lwz r3,0x0(r3) // this is pte at last 1278 /* 1279 * if (!pte_present(pte)) 1280 * 1281 */ 1282 l.andi r4,r3,0x1 1283 l.sfne r4,r0 // is pte present 1284 l.bnf i_pte_not_present 1285 l.addi r4,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK 1286 /* 1287 * fill ITLB TR register 1288 */ 1289 l.and r4,r3,r4 // apply the mask 1290 l.andi r3,r3,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE 1291 l.sfeq r3,r0 1292 l.bf itlb_tr_fill //_workaround 1293 // Determine number of IMMU sets 1294 l.mfspr r2, r0, SPR_IMMUCFGR 1295 l.andi r2, r2, SPR_IMMUCFGR_NTS 1296 l.srli r2, r2, SPR_IMMUCFGR_NTS_OFF 1297 l.ori r3, r0, 0x1 1298 l.sll r3, r3, r2 // r3 = number IMMU sets IMMUCFGR 1299 l.addi r2, r3, -1 // r2 = nsets mask 1300 l.mfspr r3, r0, SPR_EEAR_BASE 1301 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1302 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1303 1304/* 1305 * __PHX__ :: fixme 1306 * we should not just blindly set executable flags, 1307 * but it does help with ping. the clean way would be to find out 1308 * (and fix it) why stack doesn't have execution permissions 1309 */ 1310 1311itlb_tr_fill_workaround: 1312 l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) 1313itlb_tr_fill: 1314 l.mtspr r2,r4,SPR_ITLBTR_BASE(0) 1315 /* 1316 * fill DTLB MR register 1317 */ 1318 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1319 l.ori r4,r3,0x1 // set hardware valid bit: ITBL_MR entry 1320 l.mtspr r2,r4,SPR_ITLBMR_BASE(0) 1321 1322 EXCEPTION_LOAD_GPR2 1323 EXCEPTION_LOAD_GPR3 1324 EXCEPTION_LOAD_GPR4 1325 l.rfe 1326 1327i_pmd_none: 1328i_pte_not_present: 1329 EXCEPTION_LOAD_GPR2 1330 EXCEPTION_LOAD_GPR3 1331 EXCEPTION_LOAD_GPR4 1332 EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) 1333 1334/* ==============================================[ boot tlb handlers ]=== */ 1335 1336 1337/* =================================================[ debugging aids ]=== */ 1338 1339/* 1340 * DESC: Prints ASCII character stored in r7 1341 * 1342 * PRMS: r7 - a 32-bit value with an ASCII character in the first byte 1343 * position. 1344 * 1345 * PREQ: The UART at UART_BASE_ADD has to be initialized 1346 * 1347 * POST: internally used but restores: 1348 * r4 - to store UART_BASE_ADD 1349 * r5 - for loading OFF_TXFULL / THRE,TEMT 1350 * r6 - for storing bitmask (SERIAL_8250) 1351 */ 1352ENTRY(_emergency_putc) 1353 EMERGENCY_PRINT_STORE_GPR4 1354 EMERGENCY_PRINT_STORE_GPR5 1355 EMERGENCY_PRINT_STORE_GPR6 1356 1357 l.movhi r4,hi(UART_BASE_ADD) 1358 l.ori r4,r4,lo(UART_BASE_ADD) 1359 1360#if defined(CONFIG_SERIAL_LITEUART) 1361 /* Check OFF_TXFULL status */ 13621: l.lwz r5,4(r4) 1363 l.andi r5,r5,0xff 1364 l.sfnei r5,0 1365 l.bf 1b 1366 l.nop 1367 1368 /* Write character */ 1369 l.andi r7,r7,0xff 1370 l.sw 0(r4),r7 1371#elif defined(CONFIG_SERIAL_8250) 1372 /* Check UART LSR THRE (hold) bit */ 1373 l.addi r6,r0,0x20 13741: l.lbz r5,5(r4) 1375 l.andi r5,r5,0x20 1376 l.sfeq r5,r6 1377 l.bnf 1b 1378 l.nop 1379 1380 /* Write character */ 1381 l.sb 0(r4),r7 1382 1383 /* Check UART LSR THRE|TEMT (hold, empty) bits */ 1384 l.addi r6,r0,0x60 13851: l.lbz r5,5(r4) 1386 l.andi r5,r5,0x60 1387 l.sfeq r5,r6 1388 l.bnf 1b 1389 l.nop 1390#endif 1391 EMERGENCY_PRINT_LOAD_GPR6 1392 EMERGENCY_PRINT_LOAD_GPR5 1393 EMERGENCY_PRINT_LOAD_GPR4 1394 l.jr r9 1395 l.nop 1396 1397/* 1398 * DSCR: prints a string referenced by r3. 1399 * 1400 * PRMS: r3 - address of the first character of null 1401 * terminated string to be printed 1402 * 1403 * PREQ: UART at UART_BASE_ADD has to be initialized 1404 * 1405 * POST: caller should be aware that r3, r9 are changed 1406 */ 1407ENTRY(_emergency_print) 1408 EMERGENCY_PRINT_STORE_GPR7 1409 EMERGENCY_PRINT_STORE_GPR9 1410 1411 /* Load character to r7, check for null terminator */ 14122: l.lbz r7,0(r3) 1413 l.sfeqi r7,0x0 1414 l.bf 9f 1415 l.nop 1416 1417 l.jal _emergency_putc 1418 l.nop 1419 1420 /* next character */ 1421 l.j 2b 1422 l.addi r3,r3,0x1 1423 14249: 1425 EMERGENCY_PRINT_LOAD_GPR9 1426 EMERGENCY_PRINT_LOAD_GPR7 1427 l.jr r9 1428 l.nop 1429 1430/* 1431 * DSCR: prints a number in r3 in hex. 1432 * 1433 * PRMS: r3 - a 32-bit unsigned integer 1434 * 1435 * PREQ: UART at UART_BASE_ADD has to be initialized 1436 * 1437 * POST: caller should be aware that r3, r9 are changed 1438 */ 1439ENTRY(_emergency_print_nr) 1440 EMERGENCY_PRINT_STORE_GPR7 1441 EMERGENCY_PRINT_STORE_GPR8 1442 EMERGENCY_PRINT_STORE_GPR9 1443 1444 l.addi r8,r0,32 // shift register 1445 14461: /* remove leading zeros */ 1447 l.addi r8,r8,-0x4 1448 l.srl r7,r3,r8 1449 l.andi r7,r7,0xf 1450 1451 /* don't skip the last zero if number == 0x0 */ 1452 l.sfeqi r8,0x4 1453 l.bf 2f 1454 l.nop 1455 1456 l.sfeq r7,r0 1457 l.bf 1b 1458 l.nop 1459 14602: 1461 l.srl r7,r3,r8 1462 1463 l.andi r7,r7,0xf 1464 l.sflts r8,r0 1465 l.bf 9f 1466 1467 /* Numbers greater than 9 translate to a-f */ 1468 l.sfgtui r7,0x9 1469 l.bnf 8f 1470 l.nop 1471 l.addi r7,r7,0x27 1472 1473 /* Convert to ascii and output character */ 14748: l.jal _emergency_putc 1475 l.addi r7,r7,0x30 1476 1477 /* next character */ 1478 l.j 2b 1479 l.addi r8,r8,-0x4 1480 14819: 1482 EMERGENCY_PRINT_LOAD_GPR9 1483 EMERGENCY_PRINT_LOAD_GPR8 1484 EMERGENCY_PRINT_LOAD_GPR7 1485 l.jr r9 1486 l.nop 1487 1488/* 1489 * This should be used for debugging only. 1490 * It messes up the Linux early serial output 1491 * somehow, so use it sparingly and essentially 1492 * only if you need to debug something that goes wrong 1493 * before Linux gets the early serial going. 1494 * 1495 * Furthermore, you'll have to make sure you set the 1496 * UART_DEVISOR correctly according to the system 1497 * clock rate. 1498 * 1499 * 1500 */ 1501 1502 1503 1504#define SYS_CLK 20000000 1505//#define SYS_CLK 1843200 1506#define OR32_CONSOLE_BAUD 115200 1507#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD) 1508 1509ENTRY(_early_uart_init) 1510 l.movhi r3,hi(UART_BASE_ADD) 1511 l.ori r3,r3,lo(UART_BASE_ADD) 1512 1513#if defined(CONFIG_SERIAL_8250) 1514 l.addi r4,r0,0x7 1515 l.sb 0x2(r3),r4 1516 1517 l.addi r4,r0,0x0 1518 l.sb 0x1(r3),r4 1519 1520 l.addi r4,r0,0x3 1521 l.sb 0x3(r3),r4 1522 1523 l.lbz r5,3(r3) 1524 l.ori r4,r5,0x80 1525 l.sb 0x3(r3),r4 1526 l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff) 1527 l.sb UART_DLM(r3),r4 1528 l.addi r4,r0,((UART_DIVISOR) & 0x000000ff) 1529 l.sb UART_DLL(r3),r4 1530 l.sb 0x3(r3),r5 1531#endif 1532 1533 l.jr r9 1534 l.nop 1535 1536 .align 0x1000 1537 .global _secondary_evbar 1538_secondary_evbar: 1539 1540 .space 0x800 1541 /* Just disable interrupts and Return */ 1542 l.ori r3,r0,SPR_SR_SM 1543 l.mtspr r0,r3,SPR_ESR_BASE 1544 l.rfe 1545 1546 1547 .section .rodata 1548_string_unhandled_exception: 1549 .string "\r\nRunarunaround: Unhandled exception 0x\0" 1550 1551_string_epc_prefix: 1552 .string ": EPC=0x\0" 1553 1554_string_nl: 1555 .string "\r\n\0" 1556 1557 1558/* ========================================[ page aligned structures ]=== */ 1559 1560/* 1561 * .data section should be page aligned 1562 * (look into arch/openrisc/kernel/vmlinux.lds.S) 1563 */ 1564 .section .data,"aw" 1565 .align 8192 1566 .global empty_zero_page 1567empty_zero_page: 1568 .space 8192 1569 1570 .global swapper_pg_dir 1571swapper_pg_dir: 1572 .space 8192 1573 1574 .global _unhandled_stack 1575_unhandled_stack: 1576 .space 8192 1577_unhandled_stack_top: 1578 1579/* ============================================================[ EOF ]=== */ 1580