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 r28 contains log(# of cache sets) 856 */ 857 l.andi r26,r24,SPR_ICCFGR_NCS 858 l.srli r28,r26,3 859 860 /* Invalidate IC */ 861 l.addi r6,r0,0 862 l.sll r5,r14,r28 8631: 864 l.mtspr r0,r6,SPR_ICBIR 865 l.sfne r6,r5 866 l.bf 1b 867 l.add r6,r6,r14 868 869 /* Enable IC */ 870 l.mfspr r6,r0,SPR_SR 871 l.ori r6,r6,SPR_SR_ICE 872 l.mtspr r0,r6,SPR_SR 873 l.nop 874 l.nop 875 l.nop 876 l.nop 877 l.nop 878 l.nop 879 l.nop 880 l.nop 881 l.nop 882 l.nop 8839: 884 l.jr r9 885 l.nop 886 887_dc_enable: 888 /* Check if DC present and skip enabling otherwise */ 889 l.mfspr r24,r0,SPR_UPR 890 l.andi r26,r24,SPR_UPR_DCP 891 l.sfeq r26,r0 892 l.bf 9f 893 l.nop 894 895 /* Disable DC */ 896 l.mfspr r6,r0,SPR_SR 897 l.addi r5,r0,-1 898 l.xori r5,r5,SPR_SR_DCE 899 l.and r5,r6,r5 900 l.mtspr r0,r5,SPR_SR 901 902 /* Establish cache block size 903 If BS=0, 16; 904 If BS=1, 32; 905 r14 contain block size 906 */ 907 l.mfspr r24,r0,SPR_DCCFGR 908 l.andi r26,r24,SPR_DCCFGR_CBS 909 l.srli r28,r26,7 910 l.ori r30,r0,16 911 l.sll r14,r30,r28 912 913 /* Establish number of cache sets 914 r28 contains log(# of cache sets) 915 */ 916 l.andi r26,r24,SPR_DCCFGR_NCS 917 l.srli r28,r26,3 918 919 /* Invalidate DC */ 920 l.addi r6,r0,0 921 l.sll r5,r14,r28 9221: 923 l.mtspr r0,r6,SPR_DCBIR 924 l.sfne r6,r5 925 l.bf 1b 926 l.add r6,r6,r14 927 928 /* Enable DC */ 929 l.mfspr r6,r0,SPR_SR 930 l.ori r6,r6,SPR_SR_DCE 931 l.mtspr r0,r6,SPR_SR 9329: 933 l.jr r9 934 l.nop 935 936/* ===============================================[ page table masks ]=== */ 937 938#define DTLB_UP_CONVERT_MASK 0x3fa 939#define ITLB_UP_CONVERT_MASK 0x3a 940 941/* for SMP we'd have (this is a bit subtle, CC must be always set 942 * for SMP, but since we have _PAGE_PRESENT bit always defined 943 * we can just modify the mask) 944 */ 945#define DTLB_SMP_CONVERT_MASK 0x3fb 946#define ITLB_SMP_CONVERT_MASK 0x3b 947 948/* ---[ boot dtlb miss handler ]----------------------------------------- */ 949 950boot_dtlb_miss_handler: 951 952/* mask for DTLB_MR register: - (0) sets V (valid) bit, 953 * - (31-12) sets bits belonging to VPN (31-12) 954 */ 955#define DTLB_MR_MASK 0xfffff001 956 957/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit, 958 * - (4) sets A (access) bit, 959 * - (5) sets D (dirty) bit, 960 * - (8) sets SRE (superuser read) bit 961 * - (9) sets SWE (superuser write) bit 962 * - (31-12) sets bits belonging to VPN (31-12) 963 */ 964#define DTLB_TR_MASK 0xfffff332 965 966/* These are for masking out the VPN/PPN value from the MR/TR registers... 967 * it's not the same as the PFN */ 968#define VPN_MASK 0xfffff000 969#define PPN_MASK 0xfffff000 970 971 972 EXCEPTION_STORE_GPR6 973 974#if 0 975 l.mfspr r6,r0,SPR_ESR_BASE // 976 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 977 l.sfeqi r6,0 // r6 == 0x1 --> SM 978 l.bf exit_with_no_dtranslation // 979 l.nop 980#endif 981 982 /* this could be optimized by moving storing of 983 * non r6 registers here, and jumping r6 restore 984 * if not in supervisor mode 985 */ 986 987 EXCEPTION_STORE_GPR2 988 EXCEPTION_STORE_GPR3 989 EXCEPTION_STORE_GPR4 990 EXCEPTION_STORE_GPR5 991 992 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 993 994immediate_translation: 995 CLEAR_GPR(r6) 996 997 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 998 999 l.mfspr r6, r0, SPR_DMMUCFGR 1000 l.andi r6, r6, SPR_DMMUCFGR_NTS 1001 l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF 1002 l.ori r5, r0, 0x1 1003 l.sll r5, r5, r6 // r5 = number DMMU sets 1004 l.addi r6, r5, -1 // r6 = nsets mask 1005 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1006 1007 l.or r6,r6,r4 // r6 <- r4 1008 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1009 l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000 1010 l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK 1011 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry 1012 l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR 1013 1014 /* set up DTLB with no translation for EA <= 0xbfffffff */ 1015 LOAD_SYMBOL_2_GPR(r6,0xbfffffff) 1016 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA) 1017 l.bf 1f // goto out 1018 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1019 1020 tophys(r3,r4) // r3 <- PA 10211: 1022 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1023 l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000 1024 l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK 1025 l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry 1026 l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR 1027 1028 EXCEPTION_LOAD_GPR6 1029 EXCEPTION_LOAD_GPR5 1030 EXCEPTION_LOAD_GPR4 1031 EXCEPTION_LOAD_GPR3 1032 EXCEPTION_LOAD_GPR2 1033 1034 l.rfe // SR <- ESR, PC <- EPC 1035 1036exit_with_no_dtranslation: 1037 /* EA out of memory or not in supervisor mode */ 1038 EXCEPTION_LOAD_GPR6 1039 EXCEPTION_LOAD_GPR4 1040 l.j _dispatch_bus_fault 1041 1042/* ---[ boot itlb miss handler ]----------------------------------------- */ 1043 1044boot_itlb_miss_handler: 1045 1046/* mask for ITLB_MR register: - sets V (valid) bit, 1047 * - sets bits belonging to VPN (15-12) 1048 */ 1049#define ITLB_MR_MASK 0xfffff001 1050 1051/* mask for ITLB_TR register: - sets A (access) bit, 1052 * - sets SXE (superuser execute) bit 1053 * - sets bits belonging to VPN (15-12) 1054 */ 1055#define ITLB_TR_MASK 0xfffff050 1056 1057/* 1058#define VPN_MASK 0xffffe000 1059#define PPN_MASK 0xffffe000 1060*/ 1061 1062 1063 1064 EXCEPTION_STORE_GPR2 1065 EXCEPTION_STORE_GPR3 1066 EXCEPTION_STORE_GPR4 1067 EXCEPTION_STORE_GPR5 1068 EXCEPTION_STORE_GPR6 1069 1070#if 0 1071 l.mfspr r6,r0,SPR_ESR_BASE // 1072 l.andi r6,r6,SPR_SR_SM // are we in kernel mode ? 1073 l.sfeqi r6,0 // r6 == 0x1 --> SM 1074 l.bf exit_with_no_itranslation 1075 l.nop 1076#endif 1077 1078 1079 l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA 1080 1081earlyearly: 1082 CLEAR_GPR(r6) 1083 1084 l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb) 1085 1086 l.mfspr r6, r0, SPR_IMMUCFGR 1087 l.andi r6, r6, SPR_IMMUCFGR_NTS 1088 l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF 1089 l.ori r5, r0, 0x1 1090 l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR 1091 l.addi r6, r5, -1 // r6 = nsets mask 1092 l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK 1093 1094 l.or r6,r6,r4 // r6 <- r4 1095 l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff 1096 l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000 1097 l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK 1098 l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry 1099 l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR 1100 1101 /* 1102 * set up ITLB with no translation for EA <= 0x0fffffff 1103 * 1104 * we need this for head.S mapping (EA = PA). if we move all functions 1105 * which run with mmu enabled into entry.S, we might be able to eliminate this. 1106 * 1107 */ 1108 LOAD_SYMBOL_2_GPR(r6,0x0fffffff) 1109 l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA) 1110 l.bf 1f // goto out 1111 l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1) 1112 1113 tophys(r3,r4) // r3 <- PA 11141: 1115 l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff 1116 l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000 1117 l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK 1118 l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry 1119 l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR 1120 1121 EXCEPTION_LOAD_GPR6 1122 EXCEPTION_LOAD_GPR5 1123 EXCEPTION_LOAD_GPR4 1124 EXCEPTION_LOAD_GPR3 1125 EXCEPTION_LOAD_GPR2 1126 1127 l.rfe // SR <- ESR, PC <- EPC 1128 1129exit_with_no_itranslation: 1130 EXCEPTION_LOAD_GPR4 1131 EXCEPTION_LOAD_GPR6 1132 l.j _dispatch_bus_fault 1133 l.nop 1134 1135/* ====================================================================== */ 1136/* 1137 * Stuff below here shouldn't go into .head section... maybe this stuff 1138 * can be moved to entry.S ??? 1139 */ 1140 1141/* ==============================================[ DTLB miss handler ]=== */ 1142 1143/* 1144 * Comments: 1145 * Exception handlers are entered with MMU off so the following handler 1146 * needs to use physical addressing 1147 * 1148 */ 1149 1150 .text 1151ENTRY(dtlb_miss_handler) 1152 EXCEPTION_STORE_GPR2 1153 EXCEPTION_STORE_GPR3 1154 EXCEPTION_STORE_GPR4 1155 /* 1156 * get EA of the miss 1157 */ 1158 l.mfspr r2,r0,SPR_EEAR_BASE 1159 /* 1160 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1161 */ 1162 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r4 is temp 1163 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1164 l.slli r4,r4,0x2 // to get address << 2 1165 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1166 /* 1167 * if (pmd_none(*pmd)) 1168 * goto pmd_none: 1169 */ 1170 tophys (r4,r3) 1171 l.lwz r3,0x0(r4) // get *pmd value 1172 l.sfne r3,r0 1173 l.bnf d_pmd_none 1174 l.addi r3,r0,0xffffe000 // PAGE_MASK 1175 1176d_pmd_good: 1177 /* 1178 * pte = *pte_offset(pmd, daddr); 1179 */ 1180 l.lwz r4,0x0(r4) // get **pmd value 1181 l.and r4,r4,r3 // & PAGE_MASK 1182 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1183 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1184 l.slli r3,r3,0x2 // to get address << 2 1185 l.add r3,r3,r4 1186 l.lwz r3,0x0(r3) // this is pte at last 1187 /* 1188 * if (!pte_present(pte)) 1189 */ 1190 l.andi r4,r3,0x1 1191 l.sfne r4,r0 // is pte present 1192 l.bnf d_pte_not_present 1193 l.addi r4,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK 1194 /* 1195 * fill DTLB TR register 1196 */ 1197 l.and r4,r3,r4 // apply the mask 1198 // Determine number of DMMU sets 1199 l.mfspr r2, r0, SPR_DMMUCFGR 1200 l.andi r2, r2, SPR_DMMUCFGR_NTS 1201 l.srli r2, r2, SPR_DMMUCFGR_NTS_OFF 1202 l.ori r3, r0, 0x1 1203 l.sll r3, r3, r2 // r3 = number DMMU sets DMMUCFGR 1204 l.addi r2, r3, -1 // r2 = nsets mask 1205 l.mfspr r3, r0, SPR_EEAR_BASE 1206 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1207 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1208 //NUM_TLB_ENTRIES 1209 l.mtspr r2,r4,SPR_DTLBTR_BASE(0) 1210 /* 1211 * fill DTLB MR register 1212 */ 1213 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1214 l.ori r4,r3,0x1 // set hardware valid bit: DTBL_MR entry 1215 l.mtspr r2,r4,SPR_DTLBMR_BASE(0) 1216 1217 EXCEPTION_LOAD_GPR2 1218 EXCEPTION_LOAD_GPR3 1219 EXCEPTION_LOAD_GPR4 1220 l.rfe 1221d_pmd_none: 1222d_pte_not_present: 1223 EXCEPTION_LOAD_GPR2 1224 EXCEPTION_LOAD_GPR3 1225 EXCEPTION_LOAD_GPR4 1226 EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) 1227 1228/* ==============================================[ ITLB miss handler ]=== */ 1229ENTRY(itlb_miss_handler) 1230 EXCEPTION_STORE_GPR2 1231 EXCEPTION_STORE_GPR3 1232 EXCEPTION_STORE_GPR4 1233 /* 1234 * get EA of the miss 1235 */ 1236 l.mfspr r2,r0,SPR_EEAR_BASE 1237 1238 /* 1239 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); 1240 * 1241 */ 1242 GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r5 is temp 1243 l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) 1244 l.slli r4,r4,0x2 // to get address << 2 1245 l.add r3,r4,r3 // r4 is pgd_index(daddr) 1246 /* 1247 * if (pmd_none(*pmd)) 1248 * goto pmd_none: 1249 */ 1250 tophys (r4,r3) 1251 l.lwz r3,0x0(r4) // get *pmd value 1252 l.sfne r3,r0 1253 l.bnf i_pmd_none 1254 l.addi r3,r0,0xffffe000 // PAGE_MASK 1255 1256i_pmd_good: 1257 /* 1258 * pte = *pte_offset(pmd, iaddr); 1259 * 1260 */ 1261 l.lwz r4,0x0(r4) // get **pmd value 1262 l.and r4,r4,r3 // & PAGE_MASK 1263 l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR 1264 l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 1265 l.slli r3,r3,0x2 // to get address << 2 1266 l.add r3,r3,r4 1267 l.lwz r3,0x0(r3) // this is pte at last 1268 /* 1269 * if (!pte_present(pte)) 1270 * 1271 */ 1272 l.andi r4,r3,0x1 1273 l.sfne r4,r0 // is pte present 1274 l.bnf i_pte_not_present 1275 l.addi r4,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK 1276 /* 1277 * fill ITLB TR register 1278 */ 1279 l.and r4,r3,r4 // apply the mask 1280 l.andi r3,r3,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE 1281 l.sfeq r3,r0 1282 l.bf itlb_tr_fill //_workaround 1283 // Determine number of IMMU sets 1284 l.mfspr r2, r0, SPR_IMMUCFGR 1285 l.andi r2, r2, SPR_IMMUCFGR_NTS 1286 l.srli r2, r2, SPR_IMMUCFGR_NTS_OFF 1287 l.ori r3, r0, 0x1 1288 l.sll r3, r3, r2 // r3 = number IMMU sets IMMUCFGR 1289 l.addi r2, r3, -1 // r2 = nsets mask 1290 l.mfspr r3, r0, SPR_EEAR_BASE 1291 l.srli r3, r3, 0xd // >> PAGE_SHIFT 1292 l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) 1293 1294/* 1295 * __PHX__ :: fixme 1296 * we should not just blindly set executable flags, 1297 * but it does help with ping. the clean way would be to find out 1298 * (and fix it) why stack doesn't have execution permissions 1299 */ 1300 1301itlb_tr_fill_workaround: 1302 l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) 1303itlb_tr_fill: 1304 l.mtspr r2,r4,SPR_ITLBTR_BASE(0) 1305 /* 1306 * fill DTLB MR register 1307 */ 1308 l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ 1309 l.ori r4,r3,0x1 // set hardware valid bit: ITBL_MR entry 1310 l.mtspr r2,r4,SPR_ITLBMR_BASE(0) 1311 1312 EXCEPTION_LOAD_GPR2 1313 EXCEPTION_LOAD_GPR3 1314 EXCEPTION_LOAD_GPR4 1315 l.rfe 1316 1317i_pmd_none: 1318i_pte_not_present: 1319 EXCEPTION_LOAD_GPR2 1320 EXCEPTION_LOAD_GPR3 1321 EXCEPTION_LOAD_GPR4 1322 EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) 1323 1324/* ==============================================[ boot tlb handlers ]=== */ 1325 1326 1327/* =================================================[ debugging aids ]=== */ 1328 1329/* 1330 * DESC: Prints ASCII character stored in r7 1331 * 1332 * PRMS: r7 - a 32-bit value with an ASCII character in the first byte 1333 * position. 1334 * 1335 * PREQ: The UART at UART_BASE_ADD has to be initialized 1336 * 1337 * POST: internally used but restores: 1338 * r4 - to store UART_BASE_ADD 1339 * r5 - for loading OFF_TXFULL / THRE,TEMT 1340 * r6 - for storing bitmask (SERIAL_8250) 1341 */ 1342ENTRY(_emergency_putc) 1343 EMERGENCY_PRINT_STORE_GPR4 1344 EMERGENCY_PRINT_STORE_GPR5 1345 EMERGENCY_PRINT_STORE_GPR6 1346 1347 l.movhi r4,hi(UART_BASE_ADD) 1348 l.ori r4,r4,lo(UART_BASE_ADD) 1349 1350#if defined(CONFIG_SERIAL_LITEUART) 1351 /* Check OFF_TXFULL status */ 13521: l.lwz r5,4(r4) 1353 l.andi r5,r5,0xff 1354 l.sfnei r5,0 1355 l.bf 1b 1356 l.nop 1357 1358 /* Write character */ 1359 l.andi r7,r7,0xff 1360 l.sw 0(r4),r7 1361#elif defined(CONFIG_SERIAL_8250) 1362 /* Check UART LSR THRE (hold) bit */ 1363 l.addi r6,r0,0x20 13641: l.lbz r5,5(r4) 1365 l.andi r5,r5,0x20 1366 l.sfeq r5,r6 1367 l.bnf 1b 1368 l.nop 1369 1370 /* Write character */ 1371 l.sb 0(r4),r7 1372 1373 /* Check UART LSR THRE|TEMT (hold, empty) bits */ 1374 l.addi r6,r0,0x60 13751: l.lbz r5,5(r4) 1376 l.andi r5,r5,0x60 1377 l.sfeq r5,r6 1378 l.bnf 1b 1379 l.nop 1380#endif 1381 EMERGENCY_PRINT_LOAD_GPR6 1382 EMERGENCY_PRINT_LOAD_GPR5 1383 EMERGENCY_PRINT_LOAD_GPR4 1384 l.jr r9 1385 l.nop 1386 1387/* 1388 * DSCR: prints a string referenced by r3. 1389 * 1390 * PRMS: r3 - address of the first character of null 1391 * terminated string to be printed 1392 * 1393 * PREQ: UART at UART_BASE_ADD has to be initialized 1394 * 1395 * POST: caller should be aware that r3, r9 are changed 1396 */ 1397ENTRY(_emergency_print) 1398 EMERGENCY_PRINT_STORE_GPR7 1399 EMERGENCY_PRINT_STORE_GPR9 1400 1401 /* Load character to r7, check for null terminator */ 14022: l.lbz r7,0(r3) 1403 l.sfeqi r7,0x0 1404 l.bf 9f 1405 l.nop 1406 1407 l.jal _emergency_putc 1408 l.nop 1409 1410 /* next character */ 1411 l.j 2b 1412 l.addi r3,r3,0x1 1413 14149: 1415 EMERGENCY_PRINT_LOAD_GPR9 1416 EMERGENCY_PRINT_LOAD_GPR7 1417 l.jr r9 1418 l.nop 1419 1420/* 1421 * DSCR: prints a number in r3 in hex. 1422 * 1423 * PRMS: r3 - a 32-bit unsigned integer 1424 * 1425 * PREQ: UART at UART_BASE_ADD has to be initialized 1426 * 1427 * POST: caller should be aware that r3, r9 are changed 1428 */ 1429ENTRY(_emergency_print_nr) 1430 EMERGENCY_PRINT_STORE_GPR7 1431 EMERGENCY_PRINT_STORE_GPR8 1432 EMERGENCY_PRINT_STORE_GPR9 1433 1434 l.addi r8,r0,32 // shift register 1435 14361: /* remove leading zeros */ 1437 l.addi r8,r8,-0x4 1438 l.srl r7,r3,r8 1439 l.andi r7,r7,0xf 1440 1441 /* don't skip the last zero if number == 0x0 */ 1442 l.sfeqi r8,0x4 1443 l.bf 2f 1444 l.nop 1445 1446 l.sfeq r7,r0 1447 l.bf 1b 1448 l.nop 1449 14502: 1451 l.srl r7,r3,r8 1452 1453 l.andi r7,r7,0xf 1454 l.sflts r8,r0 1455 l.bf 9f 1456 1457 /* Numbers greater than 9 translate to a-f */ 1458 l.sfgtui r7,0x9 1459 l.bnf 8f 1460 l.nop 1461 l.addi r7,r7,0x27 1462 1463 /* Convert to ascii and output character */ 14648: l.jal _emergency_putc 1465 l.addi r7,r7,0x30 1466 1467 /* next character */ 1468 l.j 2b 1469 l.addi r8,r8,-0x4 1470 14719: 1472 EMERGENCY_PRINT_LOAD_GPR9 1473 EMERGENCY_PRINT_LOAD_GPR8 1474 EMERGENCY_PRINT_LOAD_GPR7 1475 l.jr r9 1476 l.nop 1477 1478/* 1479 * This should be used for debugging only. 1480 * It messes up the Linux early serial output 1481 * somehow, so use it sparingly and essentially 1482 * only if you need to debug something that goes wrong 1483 * before Linux gets the early serial going. 1484 * 1485 * Furthermore, you'll have to make sure you set the 1486 * UART_DEVISOR correctly according to the system 1487 * clock rate. 1488 * 1489 * 1490 */ 1491 1492 1493 1494#define SYS_CLK 20000000 1495//#define SYS_CLK 1843200 1496#define OR32_CONSOLE_BAUD 115200 1497#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD) 1498 1499ENTRY(_early_uart_init) 1500 l.movhi r3,hi(UART_BASE_ADD) 1501 l.ori r3,r3,lo(UART_BASE_ADD) 1502 1503#if defined(CONFIG_SERIAL_8250) 1504 l.addi r4,r0,0x7 1505 l.sb 0x2(r3),r4 1506 1507 l.addi r4,r0,0x0 1508 l.sb 0x1(r3),r4 1509 1510 l.addi r4,r0,0x3 1511 l.sb 0x3(r3),r4 1512 1513 l.lbz r5,3(r3) 1514 l.ori r4,r5,0x80 1515 l.sb 0x3(r3),r4 1516 l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff) 1517 l.sb UART_DLM(r3),r4 1518 l.addi r4,r0,((UART_DIVISOR) & 0x000000ff) 1519 l.sb UART_DLL(r3),r4 1520 l.sb 0x3(r3),r5 1521#endif 1522 1523 l.jr r9 1524 l.nop 1525 1526 .align 0x1000 1527 .global _secondary_evbar 1528_secondary_evbar: 1529 1530 .space 0x800 1531 /* Just disable interrupts and Return */ 1532 l.ori r3,r0,SPR_SR_SM 1533 l.mtspr r0,r3,SPR_ESR_BASE 1534 l.rfe 1535 1536 1537 .section .rodata 1538_string_unhandled_exception: 1539 .string "\r\nRunarunaround: Unhandled exception 0x\0" 1540 1541_string_epc_prefix: 1542 .string ": EPC=0x\0" 1543 1544_string_nl: 1545 .string "\r\n\0" 1546 1547 1548/* ========================================[ page aligned structures ]=== */ 1549 1550/* 1551 * .data section should be page aligned 1552 * (look into arch/openrisc/kernel/vmlinux.lds.S) 1553 */ 1554 .section .data,"aw" 1555 .align 8192 1556 1557 .global swapper_pg_dir 1558swapper_pg_dir: 1559 .space 8192 1560 1561 .global _unhandled_stack 1562_unhandled_stack: 1563 .space 8192 1564_unhandled_stack_top: 1565 1566/* ============================================================[ EOF ]=== */ 1567