1/* 2 * OpenRISC entry.S 3 * 4 * Linux architectural port borrowing liberally from similar works of 5 * others. All original copyrights apply as per the original source 6 * declaration. 7 * 8 * Modifications for the OpenRISC architecture: 9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 10 * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com> 11 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 16 * 2 of the License, or (at your option) any later version. 17 */ 18 19#include <linux/linkage.h> 20 21#include <asm/processor.h> 22#include <asm/unistd.h> 23#include <asm/thread_info.h> 24#include <asm/errno.h> 25#include <asm/spr_defs.h> 26#include <asm/page.h> 27#include <asm/mmu.h> 28#include <asm/pgtable.h> 29#include <asm/asm-offsets.h> 30 31#define DISABLE_INTERRUPTS(t1,t2) \ 32 l.mfspr t2,r0,SPR_SR ;\ 33 l.movhi t1,hi(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ 34 l.ori t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE)) ;\ 35 l.and t2,t2,t1 ;\ 36 l.mtspr r0,t2,SPR_SR 37 38#define ENABLE_INTERRUPTS(t1) \ 39 l.mfspr t1,r0,SPR_SR ;\ 40 l.ori t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE) ;\ 41 l.mtspr r0,t1,SPR_SR 42 43/* =========================================================[ macros ]=== */ 44 45#ifdef CONFIG_TRACE_IRQFLAGS 46/* 47 * Trace irq on/off creating a stack frame. 48 */ 49#define TRACE_IRQS_OP(trace_op) \ 50 l.sw -8(r1),r2 /* store frame pointer */ ;\ 51 l.sw -4(r1),r9 /* store return address */ ;\ 52 l.addi r2,r1,0 /* move sp to fp */ ;\ 53 l.jal trace_op ;\ 54 l.addi r1,r1,-8 ;\ 55 l.ori r1,r2,0 /* restore sp */ ;\ 56 l.lwz r9,-4(r1) /* restore return address */ ;\ 57 l.lwz r2,-8(r1) /* restore fp */ ;\ 58/* 59 * Trace irq on/off and save registers we need that would otherwise be 60 * clobbered. 61 */ 62#define TRACE_IRQS_SAVE(t1,trace_op) \ 63 l.sw -12(r1),t1 /* save extra reg */ ;\ 64 l.sw -8(r1),r2 /* store frame pointer */ ;\ 65 l.sw -4(r1),r9 /* store return address */ ;\ 66 l.addi r2,r1,0 /* move sp to fp */ ;\ 67 l.jal trace_op ;\ 68 l.addi r1,r1,-12 ;\ 69 l.ori r1,r2,0 /* restore sp */ ;\ 70 l.lwz r9,-4(r1) /* restore return address */ ;\ 71 l.lwz r2,-8(r1) /* restore fp */ ;\ 72 l.lwz t1,-12(r1) /* restore extra reg */ 73 74#define TRACE_IRQS_OFF TRACE_IRQS_OP(trace_hardirqs_off) 75#define TRACE_IRQS_ON TRACE_IRQS_OP(trace_hardirqs_on) 76#define TRACE_IRQS_ON_SYSCALL \ 77 TRACE_IRQS_SAVE(r10,trace_hardirqs_on) ;\ 78 l.lwz r3,PT_GPR3(r1) ;\ 79 l.lwz r4,PT_GPR4(r1) ;\ 80 l.lwz r5,PT_GPR5(r1) ;\ 81 l.lwz r6,PT_GPR6(r1) ;\ 82 l.lwz r7,PT_GPR7(r1) ;\ 83 l.lwz r8,PT_GPR8(r1) ;\ 84 l.lwz r11,PT_GPR11(r1) 85#define TRACE_IRQS_OFF_ENTRY \ 86 l.lwz r5,PT_SR(r1) ;\ 87 l.andi r3,r5,(SPR_SR_IEE|SPR_SR_TEE) ;\ 88 l.sfeq r5,r0 /* skip trace if irqs were already off */;\ 89 l.bf 1f ;\ 90 l.nop ;\ 91 TRACE_IRQS_SAVE(r4,trace_hardirqs_off) ;\ 921: 93#else 94#define TRACE_IRQS_OFF 95#define TRACE_IRQS_ON 96#define TRACE_IRQS_OFF_ENTRY 97#define TRACE_IRQS_ON_SYSCALL 98#endif 99 100/* 101 * We need to disable interrupts at beginning of RESTORE_ALL 102 * since interrupt might come in after we've loaded EPC return address 103 * and overwrite EPC with address somewhere in RESTORE_ALL 104 * which is of course wrong! 105 */ 106 107#define RESTORE_ALL \ 108 DISABLE_INTERRUPTS(r3,r4) ;\ 109 l.lwz r3,PT_PC(r1) ;\ 110 l.mtspr r0,r3,SPR_EPCR_BASE ;\ 111 l.lwz r3,PT_SR(r1) ;\ 112 l.mtspr r0,r3,SPR_ESR_BASE ;\ 113 l.lwz r2,PT_GPR2(r1) ;\ 114 l.lwz r3,PT_GPR3(r1) ;\ 115 l.lwz r4,PT_GPR4(r1) ;\ 116 l.lwz r5,PT_GPR5(r1) ;\ 117 l.lwz r6,PT_GPR6(r1) ;\ 118 l.lwz r7,PT_GPR7(r1) ;\ 119 l.lwz r8,PT_GPR8(r1) ;\ 120 l.lwz r9,PT_GPR9(r1) ;\ 121 l.lwz r10,PT_GPR10(r1) ;\ 122 l.lwz r11,PT_GPR11(r1) ;\ 123 l.lwz r12,PT_GPR12(r1) ;\ 124 l.lwz r13,PT_GPR13(r1) ;\ 125 l.lwz r14,PT_GPR14(r1) ;\ 126 l.lwz r15,PT_GPR15(r1) ;\ 127 l.lwz r16,PT_GPR16(r1) ;\ 128 l.lwz r17,PT_GPR17(r1) ;\ 129 l.lwz r18,PT_GPR18(r1) ;\ 130 l.lwz r19,PT_GPR19(r1) ;\ 131 l.lwz r20,PT_GPR20(r1) ;\ 132 l.lwz r21,PT_GPR21(r1) ;\ 133 l.lwz r22,PT_GPR22(r1) ;\ 134 l.lwz r23,PT_GPR23(r1) ;\ 135 l.lwz r24,PT_GPR24(r1) ;\ 136 l.lwz r25,PT_GPR25(r1) ;\ 137 l.lwz r26,PT_GPR26(r1) ;\ 138 l.lwz r27,PT_GPR27(r1) ;\ 139 l.lwz r28,PT_GPR28(r1) ;\ 140 l.lwz r29,PT_GPR29(r1) ;\ 141 l.lwz r30,PT_GPR30(r1) ;\ 142 l.lwz r31,PT_GPR31(r1) ;\ 143 l.lwz r1,PT_SP(r1) ;\ 144 l.rfe 145 146 147#define EXCEPTION_ENTRY(handler) \ 148 .global handler ;\ 149handler: ;\ 150 /* r1, EPCR, ESR a already saved */ ;\ 151 l.sw PT_GPR2(r1),r2 ;\ 152 l.sw PT_GPR3(r1),r3 ;\ 153 /* r4 already save */ ;\ 154 l.sw PT_GPR5(r1),r5 ;\ 155 l.sw PT_GPR6(r1),r6 ;\ 156 l.sw PT_GPR7(r1),r7 ;\ 157 l.sw PT_GPR8(r1),r8 ;\ 158 l.sw PT_GPR9(r1),r9 ;\ 159 /* r10 already saved */ ;\ 160 l.sw PT_GPR11(r1),r11 ;\ 161 /* r12 already saved */ ;\ 162 l.sw PT_GPR13(r1),r13 ;\ 163 l.sw PT_GPR14(r1),r14 ;\ 164 l.sw PT_GPR15(r1),r15 ;\ 165 l.sw PT_GPR16(r1),r16 ;\ 166 l.sw PT_GPR17(r1),r17 ;\ 167 l.sw PT_GPR18(r1),r18 ;\ 168 l.sw PT_GPR19(r1),r19 ;\ 169 l.sw PT_GPR20(r1),r20 ;\ 170 l.sw PT_GPR21(r1),r21 ;\ 171 l.sw PT_GPR22(r1),r22 ;\ 172 l.sw PT_GPR23(r1),r23 ;\ 173 l.sw PT_GPR24(r1),r24 ;\ 174 l.sw PT_GPR25(r1),r25 ;\ 175 l.sw PT_GPR26(r1),r26 ;\ 176 l.sw PT_GPR27(r1),r27 ;\ 177 l.sw PT_GPR28(r1),r28 ;\ 178 l.sw PT_GPR29(r1),r29 ;\ 179 /* r30 already save */ ;\ 180/* l.sw PT_GPR30(r1),r30*/ ;\ 181 l.sw PT_GPR31(r1),r31 ;\ 182 TRACE_IRQS_OFF_ENTRY ;\ 183 /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 184 l.addi r30,r0,-1 ;\ 185 l.sw PT_ORIG_GPR11(r1),r30 186 187#define UNHANDLED_EXCEPTION(handler,vector) \ 188 .global handler ;\ 189handler: ;\ 190 /* r1, EPCR, ESR already saved */ ;\ 191 l.sw PT_GPR2(r1),r2 ;\ 192 l.sw PT_GPR3(r1),r3 ;\ 193 l.sw PT_GPR5(r1),r5 ;\ 194 l.sw PT_GPR6(r1),r6 ;\ 195 l.sw PT_GPR7(r1),r7 ;\ 196 l.sw PT_GPR8(r1),r8 ;\ 197 l.sw PT_GPR9(r1),r9 ;\ 198 /* r10 already saved */ ;\ 199 l.sw PT_GPR11(r1),r11 ;\ 200 /* r12 already saved */ ;\ 201 l.sw PT_GPR13(r1),r13 ;\ 202 l.sw PT_GPR14(r1),r14 ;\ 203 l.sw PT_GPR15(r1),r15 ;\ 204 l.sw PT_GPR16(r1),r16 ;\ 205 l.sw PT_GPR17(r1),r17 ;\ 206 l.sw PT_GPR18(r1),r18 ;\ 207 l.sw PT_GPR19(r1),r19 ;\ 208 l.sw PT_GPR20(r1),r20 ;\ 209 l.sw PT_GPR21(r1),r21 ;\ 210 l.sw PT_GPR22(r1),r22 ;\ 211 l.sw PT_GPR23(r1),r23 ;\ 212 l.sw PT_GPR24(r1),r24 ;\ 213 l.sw PT_GPR25(r1),r25 ;\ 214 l.sw PT_GPR26(r1),r26 ;\ 215 l.sw PT_GPR27(r1),r27 ;\ 216 l.sw PT_GPR28(r1),r28 ;\ 217 l.sw PT_GPR29(r1),r29 ;\ 218 /* r31 already saved */ ;\ 219 l.sw PT_GPR30(r1),r30 ;\ 220/* l.sw PT_GPR31(r1),r31 */ ;\ 221 /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ 222 l.addi r30,r0,-1 ;\ 223 l.sw PT_ORIG_GPR11(r1),r30 ;\ 224 l.addi r3,r1,0 ;\ 225 /* r4 is exception EA */ ;\ 226 l.addi r5,r0,vector ;\ 227 l.jal unhandled_exception ;\ 228 l.nop ;\ 229 l.j _ret_from_exception ;\ 230 l.nop 231 232/* clobbers 'reg' */ 233#define CLEAR_LWA_FLAG(reg) \ 234 l.movhi reg,hi(lwa_flag) ;\ 235 l.ori reg,reg,lo(lwa_flag) ;\ 236 l.sw 0(reg),r0 237/* 238 * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR 239 * contain the same values as when exception we're handling 240 * occured. in fact they never do. if you need them use 241 * values saved on stack (for SPR_EPC, SPR_ESR) or content 242 * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() 243 * in 'arch/or32/kernel/head.S' 244 */ 245 246/* =====================================================[ exceptions] === */ 247 248/* ---[ 0x100: RESET exception ]----------------------------------------- */ 249 250EXCEPTION_ENTRY(_tng_kernel_start) 251 l.jal _start 252 l.andi r0,r0,0 253 254/* ---[ 0x200: BUS exception ]------------------------------------------- */ 255 256EXCEPTION_ENTRY(_bus_fault_handler) 257 CLEAR_LWA_FLAG(r3) 258 /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 259 l.jal do_bus_fault 260 l.addi r3,r1,0 /* pt_regs */ 261 262 l.j _ret_from_exception 263 l.nop 264 265/* ---[ 0x300: Data Page Fault exception ]------------------------------- */ 266EXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) 267 CLEAR_LWA_FLAG(r3) 268 l.and r5,r5,r0 269 l.j 1f 270 l.nop 271 272EXCEPTION_ENTRY(_data_page_fault_handler) 273 CLEAR_LWA_FLAG(r3) 274 /* set up parameters for do_page_fault */ 275 l.ori r5,r0,0x300 // exception vector 2761: 277 l.addi r3,r1,0 // pt_regs 278 /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 279 280 /* 281 * __PHX__: TODO 282 * 283 * all this can be written much simpler. look at 284 * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part 285 */ 286#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX 287 l.lwz r6,PT_PC(r3) // address of an offending insn 288 l.lwz r6,0(r6) // instruction that caused pf 289 290 l.srli r6,r6,26 // check opcode for jump insn 291 l.sfeqi r6,0 // l.j 292 l.bf 8f 293 l.sfeqi r6,1 // l.jal 294 l.bf 8f 295 l.sfeqi r6,3 // l.bnf 296 l.bf 8f 297 l.sfeqi r6,4 // l.bf 298 l.bf 8f 299 l.sfeqi r6,0x11 // l.jr 300 l.bf 8f 301 l.sfeqi r6,0x12 // l.jalr 302 l.bf 8f 303 l.nop 304 305 l.j 9f 306 l.nop 307 3088: // offending insn is in delay slot 309 l.lwz r6,PT_PC(r3) // address of an offending insn 310 l.addi r6,r6,4 311 l.lwz r6,0(r6) // instruction that caused pf 312 l.srli r6,r6,26 // get opcode 3139: // offending instruction opcode loaded in r6 314 315#else 316 317 l.lwz r6,PT_SR(r3) // SR 318 l.andi r6,r6,SPR_SR_DSX // check for delay slot exception 319 l.sfne r6,r0 // exception happened in delay slot 320 l.bnf 7f 321 l.lwz r6,PT_PC(r3) // address of an offending insn 322 323 l.addi r6,r6,4 // offending insn is in delay slot 3247: 325 l.lwz r6,0(r6) // instruction that caused pf 326 l.srli r6,r6,26 // check opcode for write access 327#endif 328 329 l.sfgeui r6,0x33 // check opcode for write access 330 l.bnf 1f 331 l.sfleui r6,0x37 332 l.bnf 1f 333 l.ori r6,r0,0x1 // write access 334 l.j 2f 335 l.nop 3361: l.ori r6,r0,0x0 // !write access 3372: 338 339 /* call fault.c handler in or32/mm/fault.c */ 340 l.jal do_page_fault 341 l.nop 342 l.j _ret_from_exception 343 l.nop 344 345/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ 346EXCEPTION_ENTRY(_itlb_miss_page_fault_handler) 347 CLEAR_LWA_FLAG(r3) 348 l.and r5,r5,r0 349 l.j 1f 350 l.nop 351 352EXCEPTION_ENTRY(_insn_page_fault_handler) 353 CLEAR_LWA_FLAG(r3) 354 /* set up parameters for do_page_fault */ 355 l.ori r5,r0,0x400 // exception vector 3561: 357 l.addi r3,r1,0 // pt_regs 358 /* r4 set be EXCEPTION_HANDLE */ // effective address of fault 359 l.ori r6,r0,0x0 // !write access 360 361 /* call fault.c handler in or32/mm/fault.c */ 362 l.jal do_page_fault 363 l.nop 364 l.j _ret_from_exception 365 l.nop 366 367 368/* ---[ 0x500: Timer exception ]----------------------------------------- */ 369 370EXCEPTION_ENTRY(_timer_handler) 371 CLEAR_LWA_FLAG(r3) 372 l.jal timer_interrupt 373 l.addi r3,r1,0 /* pt_regs */ 374 375 l.j _ret_from_intr 376 l.nop 377 378/* ---[ 0x600: Alignment exception ]-------------------------------------- */ 379 380EXCEPTION_ENTRY(_alignment_handler) 381 CLEAR_LWA_FLAG(r3) 382 /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 383 l.jal do_unaligned_access 384 l.addi r3,r1,0 /* pt_regs */ 385 386 l.j _ret_from_exception 387 l.nop 388 389#if 0 390EXCEPTION_ENTRY(_alignment_handler) 391// l.mfspr r2,r0,SPR_EEAR_BASE /* Load the effective address */ 392 l.addi r2,r4,0 393// l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */ 394 l.lwz r5,PT_PC(r1) 395 396 l.lwz r3,0(r5) /* Load insn */ 397 l.srli r4,r3,26 /* Shift left to get the insn opcode */ 398 399 l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */ 400 l.bf jmp 401 l.sfeqi r4,0x01 402 l.bf jmp 403 l.sfeqi r4,0x03 404 l.bf jmp 405 l.sfeqi r4,0x04 406 l.bf jmp 407 l.sfeqi r4,0x11 408 l.bf jr 409 l.sfeqi r4,0x12 410 l.bf jr 411 l.nop 412 l.j 1f 413 l.addi r5,r5,4 /* Increment PC to get return insn address */ 414 415jmp: 416 l.slli r4,r3,6 /* Get the signed extended jump length */ 417 l.srai r4,r4,4 418 419 l.lwz r3,4(r5) /* Load the real load/store insn */ 420 421 l.add r5,r5,r4 /* Calculate jump target address */ 422 423 l.j 1f 424 l.srli r4,r3,26 /* Shift left to get the insn opcode */ 425 426jr: 427 l.slli r4,r3,9 /* Shift to get the reg nb */ 428 l.andi r4,r4,0x7c 429 430 l.lwz r3,4(r5) /* Load the real load/store insn */ 431 432 l.add r4,r4,r1 /* Load the jump register value from the stack */ 433 l.lwz r5,0(r4) 434 435 l.srli r4,r3,26 /* Shift left to get the insn opcode */ 436 437 4381: 439// l.mtspr r0,r5,SPR_EPCR_BASE 440 l.sw PT_PC(r1),r5 441 442 l.sfeqi r4,0x26 443 l.bf lhs 444 l.sfeqi r4,0x25 445 l.bf lhz 446 l.sfeqi r4,0x22 447 l.bf lws 448 l.sfeqi r4,0x21 449 l.bf lwz 450 l.sfeqi r4,0x37 451 l.bf sh 452 l.sfeqi r4,0x35 453 l.bf sw 454 l.nop 455 4561: l.j 1b /* I don't know what to do */ 457 l.nop 458 459lhs: l.lbs r5,0(r2) 460 l.slli r5,r5,8 461 l.lbz r6,1(r2) 462 l.or r5,r5,r6 463 l.srli r4,r3,19 464 l.andi r4,r4,0x7c 465 l.add r4,r4,r1 466 l.j align_end 467 l.sw 0(r4),r5 468 469lhz: l.lbz r5,0(r2) 470 l.slli r5,r5,8 471 l.lbz r6,1(r2) 472 l.or r5,r5,r6 473 l.srli r4,r3,19 474 l.andi r4,r4,0x7c 475 l.add r4,r4,r1 476 l.j align_end 477 l.sw 0(r4),r5 478 479lws: l.lbs r5,0(r2) 480 l.slli r5,r5,24 481 l.lbz r6,1(r2) 482 l.slli r6,r6,16 483 l.or r5,r5,r6 484 l.lbz r6,2(r2) 485 l.slli r6,r6,8 486 l.or r5,r5,r6 487 l.lbz r6,3(r2) 488 l.or r5,r5,r6 489 l.srli r4,r3,19 490 l.andi r4,r4,0x7c 491 l.add r4,r4,r1 492 l.j align_end 493 l.sw 0(r4),r5 494 495lwz: l.lbz r5,0(r2) 496 l.slli r5,r5,24 497 l.lbz r6,1(r2) 498 l.slli r6,r6,16 499 l.or r5,r5,r6 500 l.lbz r6,2(r2) 501 l.slli r6,r6,8 502 l.or r5,r5,r6 503 l.lbz r6,3(r2) 504 l.or r5,r5,r6 505 l.srli r4,r3,19 506 l.andi r4,r4,0x7c 507 l.add r4,r4,r1 508 l.j align_end 509 l.sw 0(r4),r5 510 511sh: 512 l.srli r4,r3,9 513 l.andi r4,r4,0x7c 514 l.add r4,r4,r1 515 l.lwz r5,0(r4) 516 l.sb 1(r2),r5 517 l.srli r5,r5,8 518 l.j align_end 519 l.sb 0(r2),r5 520 521sw: 522 l.srli r4,r3,9 523 l.andi r4,r4,0x7c 524 l.add r4,r4,r1 525 l.lwz r5,0(r4) 526 l.sb 3(r2),r5 527 l.srli r5,r5,8 528 l.sb 2(r2),r5 529 l.srli r5,r5,8 530 l.sb 1(r2),r5 531 l.srli r5,r5,8 532 l.j align_end 533 l.sb 0(r2),r5 534 535align_end: 536 l.j _ret_from_intr 537 l.nop 538#endif 539 540/* ---[ 0x700: Illegal insn exception ]---------------------------------- */ 541 542EXCEPTION_ENTRY(_illegal_instruction_handler) 543 /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 544 l.jal do_illegal_instruction 545 l.addi r3,r1,0 /* pt_regs */ 546 547 l.j _ret_from_exception 548 l.nop 549 550/* ---[ 0x800: External interrupt exception ]---------------------------- */ 551 552EXCEPTION_ENTRY(_external_irq_handler) 553#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK 554 l.lwz r4,PT_SR(r1) // were interrupts enabled ? 555 l.andi r4,r4,SPR_SR_IEE 556 l.sfeqi r4,0 557 l.bnf 1f // ext irq enabled, all ok. 558 l.nop 559 560 l.addi r1,r1,-0x8 561 l.movhi r3,hi(42f) 562 l.ori r3,r3,lo(42f) 563 l.sw 0x0(r1),r3 564 l.jal printk 565 l.sw 0x4(r1),r4 566 l.addi r1,r1,0x8 567 568 .section .rodata, "a" 56942: 570 .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r" 571 .align 4 572 .previous 573 574 l.ori r4,r4,SPR_SR_IEE // fix the bug 575// l.sw PT_SR(r1),r4 5761: 577#endif 578 CLEAR_LWA_FLAG(r3) 579 l.addi r3,r1,0 580 l.movhi r8,hi(do_IRQ) 581 l.ori r8,r8,lo(do_IRQ) 582 l.jalr r8 583 l.nop 584 l.j _ret_from_intr 585 l.nop 586 587/* ---[ 0x900: DTLB miss exception ]------------------------------------- */ 588 589 590/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */ 591 592 593/* ---[ 0xb00: Range exception ]----------------------------------------- */ 594 595UNHANDLED_EXCEPTION(_vector_0xb00,0xb00) 596 597/* ---[ 0xc00: Syscall exception ]--------------------------------------- */ 598 599/* 600 * Syscalls are a special type of exception in that they are 601 * _explicitly_ invoked by userspace and can therefore be 602 * held to conform to the same ABI as normal functions with 603 * respect to whether registers are preserved across the call 604 * or not. 605 */ 606 607/* Upon syscall entry we just save the callee-saved registers 608 * and not the call-clobbered ones. 609 */ 610 611_string_syscall_return: 612 .string "syscall return %ld \n\r\0" 613 .align 4 614 615ENTRY(_sys_call_handler) 616 /* r1, EPCR, ESR a already saved */ 617 l.sw PT_GPR2(r1),r2 618 /* r3-r8 must be saved because syscall restart relies 619 * on us being able to restart the syscall args... technically 620 * they should be clobbered, otherwise 621 */ 622 l.sw PT_GPR3(r1),r3 623 /* 624 * r4 already saved 625 * r4 holds the EEAR address of the fault, use it as screatch reg and 626 * then load the original r4 627 */ 628 CLEAR_LWA_FLAG(r4) 629 l.lwz r4,PT_GPR4(r1) 630 l.sw PT_GPR5(r1),r5 631 l.sw PT_GPR6(r1),r6 632 l.sw PT_GPR7(r1),r7 633 l.sw PT_GPR8(r1),r8 634 l.sw PT_GPR9(r1),r9 635 /* r10 already saved */ 636 l.sw PT_GPR11(r1),r11 637 /* orig_gpr11 must be set for syscalls */ 638 l.sw PT_ORIG_GPR11(r1),r11 639 /* r12,r13 already saved */ 640 641 /* r14-r28 (even) aren't touched by the syscall fast path below 642 * so we don't need to save them. However, the functions that return 643 * to userspace via a call to switch() DO need to save these because 644 * switch() effectively clobbers them... saving these registers for 645 * such functions is handled in their syscall wrappers (see fork, vfork, 646 * and clone, below). 647 648 /* r30 is the only register we clobber in the fast path */ 649 /* r30 already saved */ 650/* l.sw PT_GPR30(r1),r30 */ 651 652_syscall_check_trace_enter: 653 /* syscalls run with interrupts enabled */ 654 TRACE_IRQS_ON_SYSCALL 655 ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp 656 657 /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */ 658 l.lwz r30,TI_FLAGS(r10) 659 l.andi r30,r30,_TIF_SYSCALL_TRACE 660 l.sfne r30,r0 661 l.bf _syscall_trace_enter 662 l.nop 663 664_syscall_check: 665 /* Ensure that the syscall number is reasonable */ 666 l.sfgeui r11,__NR_syscalls 667 l.bf _syscall_badsys 668 l.nop 669 670_syscall_call: 671 l.movhi r29,hi(sys_call_table) 672 l.ori r29,r29,lo(sys_call_table) 673 l.slli r11,r11,2 674 l.add r29,r29,r11 675 l.lwz r29,0(r29) 676 677 l.jalr r29 678 l.nop 679 680_syscall_return: 681 /* All syscalls return here... just pay attention to ret_from_fork 682 * which does it in a round-about way. 683 */ 684 l.sw PT_GPR11(r1),r11 // save return value 685 686#if 0 687_syscall_debug: 688 l.movhi r3,hi(_string_syscall_return) 689 l.ori r3,r3,lo(_string_syscall_return) 690 l.ori r27,r0,1 691 l.sw -4(r1),r27 692 l.sw -8(r1),r11 693 l.addi r1,r1,-8 694 l.movhi r27,hi(printk) 695 l.ori r27,r27,lo(printk) 696 l.jalr r27 697 l.nop 698 l.addi r1,r1,8 699#endif 700 701_syscall_check_trace_leave: 702 /* r30 is a callee-saved register so this should still hold the 703 * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above... 704 * _syscall_trace_leave expects syscall result to be in pt_regs->r11. 705 */ 706 l.sfne r30,r0 707 l.bf _syscall_trace_leave 708 l.nop 709 710/* This is where the exception-return code begins... interrupts need to be 711 * disabled the rest of the way here because we can't afford to miss any 712 * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */ 713 714_syscall_check_work: 715 /* Here we need to disable interrupts */ 716 DISABLE_INTERRUPTS(r27,r29) 717 TRACE_IRQS_OFF 718 l.lwz r30,TI_FLAGS(r10) 719 l.andi r30,r30,_TIF_WORK_MASK 720 l.sfne r30,r0 721 722 l.bnf _syscall_resume_userspace 723 l.nop 724 725 /* Work pending follows a different return path, so we need to 726 * make sure that all the call-saved registers get into pt_regs 727 * before branching... 728 */ 729 l.sw PT_GPR14(r1),r14 730 l.sw PT_GPR16(r1),r16 731 l.sw PT_GPR18(r1),r18 732 l.sw PT_GPR20(r1),r20 733 l.sw PT_GPR22(r1),r22 734 l.sw PT_GPR24(r1),r24 735 l.sw PT_GPR26(r1),r26 736 l.sw PT_GPR28(r1),r28 737 738 /* _work_pending needs to be called with interrupts disabled */ 739 l.j _work_pending 740 l.nop 741 742_syscall_resume_userspace: 743// ENABLE_INTERRUPTS(r29) 744 745 746/* This is the hot path for returning to userspace from a syscall. If there's 747 * work to be done and the branch to _work_pending was taken above, then the 748 * return to userspace will be done via the normal exception return path... 749 * that path restores _all_ registers and will overwrite the "clobbered" 750 * registers with whatever garbage is in pt_regs -- that's OK because those 751 * registers are clobbered anyway and because the extra work is insignificant 752 * in the context of the extra work that _work_pending is doing. 753 754/* Once again, syscalls are special and only guarantee to preserve the 755 * same registers as a normal function call */ 756 757/* The assumption here is that the registers r14-r28 (even) are untouched and 758 * don't need to be restored... be sure that that's really the case! 759 */ 760 761/* This is still too much... we should only be restoring what we actually 762 * clobbered... we should even be using 'scratch' (odd) regs above so that 763 * we don't need to restore anything, hardly... 764 */ 765 766 l.lwz r2,PT_GPR2(r1) 767 768 /* Restore args */ 769 /* r3-r8 are technically clobbered, but syscall restart needs these 770 * to be restored... 771 */ 772 l.lwz r3,PT_GPR3(r1) 773 l.lwz r4,PT_GPR4(r1) 774 l.lwz r5,PT_GPR5(r1) 775 l.lwz r6,PT_GPR6(r1) 776 l.lwz r7,PT_GPR7(r1) 777 l.lwz r8,PT_GPR8(r1) 778 779 l.lwz r9,PT_GPR9(r1) 780 l.lwz r10,PT_GPR10(r1) 781 l.lwz r11,PT_GPR11(r1) 782 783 /* r30 is the only register we clobber in the fast path */ 784 l.lwz r30,PT_GPR30(r1) 785 786 /* Here we use r13-r19 (odd) as scratch regs */ 787 l.lwz r13,PT_PC(r1) 788 l.lwz r15,PT_SR(r1) 789 l.lwz r1,PT_SP(r1) 790 /* Interrupts need to be disabled for setting EPCR and ESR 791 * so that another interrupt doesn't come in here and clobber 792 * them before we can use them for our l.rfe */ 793 DISABLE_INTERRUPTS(r17,r19) 794 l.mtspr r0,r13,SPR_EPCR_BASE 795 l.mtspr r0,r15,SPR_ESR_BASE 796 l.rfe 797 798/* End of hot path! 799 * Keep the below tracing and error handling out of the hot path... 800*/ 801 802_syscall_trace_enter: 803 /* Here we pass pt_regs to do_syscall_trace_enter. Make sure 804 * that function is really getting all the info it needs as 805 * pt_regs isn't a complete set of userspace regs, just the 806 * ones relevant to the syscall... 807 * 808 * Note use of delay slot for setting argument. 809 */ 810 l.jal do_syscall_trace_enter 811 l.addi r3,r1,0 812 813 /* Restore arguments (not preserved across do_syscall_trace_enter) 814 * so that we can do the syscall for real and return to the syscall 815 * hot path. 816 */ 817 l.lwz r11,PT_GPR11(r1) 818 l.lwz r3,PT_GPR3(r1) 819 l.lwz r4,PT_GPR4(r1) 820 l.lwz r5,PT_GPR5(r1) 821 l.lwz r6,PT_GPR6(r1) 822 l.lwz r7,PT_GPR7(r1) 823 824 l.j _syscall_check 825 l.lwz r8,PT_GPR8(r1) 826 827_syscall_trace_leave: 828 l.jal do_syscall_trace_leave 829 l.addi r3,r1,0 830 831 l.j _syscall_check_work 832 l.nop 833 834_syscall_badsys: 835 /* Here we effectively pretend to have executed an imaginary 836 * syscall that returns -ENOSYS and then return to the regular 837 * syscall hot path. 838 * Note that "return value" is set in the delay slot... 839 */ 840 l.j _syscall_return 841 l.addi r11,r0,-ENOSYS 842 843/******* END SYSCALL HANDLING *******/ 844 845/* ---[ 0xd00: Trap exception ]------------------------------------------ */ 846 847UNHANDLED_EXCEPTION(_vector_0xd00,0xd00) 848 849/* ---[ 0xe00: Trap exception ]------------------------------------------ */ 850 851EXCEPTION_ENTRY(_trap_handler) 852 CLEAR_LWA_FLAG(r3) 853 /* r4: EA of fault (set by EXCEPTION_HANDLE) */ 854 l.jal do_trap 855 l.addi r3,r1,0 /* pt_regs */ 856 857 l.j _ret_from_exception 858 l.nop 859 860/* ---[ 0xf00: Reserved exception ]-------------------------------------- */ 861 862UNHANDLED_EXCEPTION(_vector_0xf00,0xf00) 863 864/* ---[ 0x1000: Reserved exception ]------------------------------------- */ 865 866UNHANDLED_EXCEPTION(_vector_0x1000,0x1000) 867 868/* ---[ 0x1100: Reserved exception ]------------------------------------- */ 869 870UNHANDLED_EXCEPTION(_vector_0x1100,0x1100) 871 872/* ---[ 0x1200: Reserved exception ]------------------------------------- */ 873 874UNHANDLED_EXCEPTION(_vector_0x1200,0x1200) 875 876/* ---[ 0x1300: Reserved exception ]------------------------------------- */ 877 878UNHANDLED_EXCEPTION(_vector_0x1300,0x1300) 879 880/* ---[ 0x1400: Reserved exception ]------------------------------------- */ 881 882UNHANDLED_EXCEPTION(_vector_0x1400,0x1400) 883 884/* ---[ 0x1500: Reserved exception ]------------------------------------- */ 885 886UNHANDLED_EXCEPTION(_vector_0x1500,0x1500) 887 888/* ---[ 0x1600: Reserved exception ]------------------------------------- */ 889 890UNHANDLED_EXCEPTION(_vector_0x1600,0x1600) 891 892/* ---[ 0x1700: Reserved exception ]------------------------------------- */ 893 894UNHANDLED_EXCEPTION(_vector_0x1700,0x1700) 895 896/* ---[ 0x1800: Reserved exception ]------------------------------------- */ 897 898UNHANDLED_EXCEPTION(_vector_0x1800,0x1800) 899 900/* ---[ 0x1900: Reserved exception ]------------------------------------- */ 901 902UNHANDLED_EXCEPTION(_vector_0x1900,0x1900) 903 904/* ---[ 0x1a00: Reserved exception ]------------------------------------- */ 905 906UNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00) 907 908/* ---[ 0x1b00: Reserved exception ]------------------------------------- */ 909 910UNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00) 911 912/* ---[ 0x1c00: Reserved exception ]------------------------------------- */ 913 914UNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00) 915 916/* ---[ 0x1d00: Reserved exception ]------------------------------------- */ 917 918UNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00) 919 920/* ---[ 0x1e00: Reserved exception ]------------------------------------- */ 921 922UNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00) 923 924/* ---[ 0x1f00: Reserved exception ]------------------------------------- */ 925 926UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) 927 928/* ========================================================[ return ] === */ 929 930_resume_userspace: 931 DISABLE_INTERRUPTS(r3,r4) 932 TRACE_IRQS_OFF 933 l.lwz r4,TI_FLAGS(r10) 934 l.andi r13,r4,_TIF_WORK_MASK 935 l.sfeqi r13,0 936 l.bf _restore_all 937 l.nop 938 939_work_pending: 940 l.lwz r5,PT_ORIG_GPR11(r1) 941 l.sfltsi r5,0 942 l.bnf 1f 943 l.nop 944 l.andi r5,r5,0 9451: 946 l.jal do_work_pending 947 l.ori r3,r1,0 /* pt_regs */ 948 949 l.sfeqi r11,0 950 l.bf _restore_all 951 l.nop 952 l.sfltsi r11,0 953 l.bnf 1f 954 l.nop 955 l.and r11,r11,r0 956 l.ori r11,r11,__NR_restart_syscall 957 l.j _syscall_check_trace_enter 958 l.nop 9591: 960 l.lwz r11,PT_ORIG_GPR11(r1) 961 /* Restore arg registers */ 962 l.lwz r3,PT_GPR3(r1) 963 l.lwz r4,PT_GPR4(r1) 964 l.lwz r5,PT_GPR5(r1) 965 l.lwz r6,PT_GPR6(r1) 966 l.lwz r7,PT_GPR7(r1) 967 l.j _syscall_check_trace_enter 968 l.lwz r8,PT_GPR8(r1) 969 970_restore_all: 971#ifdef CONFIG_TRACE_IRQFLAGS 972 l.lwz r4,PT_SR(r1) 973 l.andi r3,r4,(SPR_SR_IEE|SPR_SR_TEE) 974 l.sfeq r3,r0 /* skip trace if irqs were off */ 975 l.bf skip_hardirqs_on 976 l.nop 977 TRACE_IRQS_ON 978skip_hardirqs_on: 979#endif 980 RESTORE_ALL 981 /* This returns to userspace code */ 982 983 984ENTRY(_ret_from_intr) 985ENTRY(_ret_from_exception) 986 l.lwz r4,PT_SR(r1) 987 l.andi r3,r4,SPR_SR_SM 988 l.sfeqi r3,0 989 l.bnf _restore_all 990 l.nop 991 l.j _resume_userspace 992 l.nop 993 994ENTRY(ret_from_fork) 995 l.jal schedule_tail 996 l.nop 997 998 /* Check if we are a kernel thread */ 999 l.sfeqi r20,0 1000 l.bf 1f 1001 l.nop 1002 1003 /* ...we are a kernel thread so invoke the requested callback */ 1004 l.jalr r20 1005 l.or r3,r22,r0 1006 10071: 1008 /* _syscall_returns expect r11 to contain return value */ 1009 l.lwz r11,PT_GPR11(r1) 1010 1011 /* The syscall fast path return expects call-saved registers 1012 * r12-r28 to be untouched, so we restore them here as they 1013 * will have been effectively clobbered when arriving here 1014 * via the call to switch() 1015 */ 1016 l.lwz r12,PT_GPR12(r1) 1017 l.lwz r14,PT_GPR14(r1) 1018 l.lwz r16,PT_GPR16(r1) 1019 l.lwz r18,PT_GPR18(r1) 1020 l.lwz r20,PT_GPR20(r1) 1021 l.lwz r22,PT_GPR22(r1) 1022 l.lwz r24,PT_GPR24(r1) 1023 l.lwz r26,PT_GPR26(r1) 1024 l.lwz r28,PT_GPR28(r1) 1025 1026 l.j _syscall_return 1027 l.nop 1028 1029/* ========================================================[ switch ] === */ 1030 1031/* 1032 * This routine switches between two different tasks. The process 1033 * state of one is saved on its kernel stack. Then the state 1034 * of the other is restored from its kernel stack. The memory 1035 * management hardware is updated to the second process's state. 1036 * Finally, we can return to the second process, via the 'return'. 1037 * 1038 * Note: there are two ways to get to the "going out" portion 1039 * of this code; either by coming in via the entry (_switch) 1040 * or via "fork" which must set up an environment equivalent 1041 * to the "_switch" path. If you change this (or in particular, the 1042 * SAVE_REGS macro), you'll have to change the fork code also. 1043 */ 1044 1045 1046/* _switch MUST never lay on page boundry, cause it runs from 1047 * effective addresses and beeing interrupted by iTLB miss would kill it. 1048 * dTLB miss seams to never accour in the bad place since data accesses 1049 * are from task structures which are always page aligned. 1050 * 1051 * The problem happens in RESTORE_ALL_NO_R11 where we first set the EPCR 1052 * register, then load the previous register values and only at the end call 1053 * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets 1054 * garbled and we end up calling l.rfe with the wrong EPCR. (same probably 1055 * holds for ESR) 1056 * 1057 * To avoid this problems it is sufficient to align _switch to 1058 * some nice round number smaller than it's size... 1059 */ 1060 1061/* ABI rules apply here... we either enter _switch via schedule() or via 1062 * an imaginary call to which we shall return at return_from_fork. Either 1063 * way, we are a function call and only need to preserve the callee-saved 1064 * registers when we return. As such, we don't need to save the registers 1065 * on the stack that we won't be returning as they were... 1066 */ 1067 1068 .align 0x400 1069ENTRY(_switch) 1070 /* We don't store SR as _switch only gets called in a context where 1071 * the SR will be the same going in and coming out... */ 1072 1073 /* Set up new pt_regs struct for saving task state */ 1074 l.addi r1,r1,-(INT_FRAME_SIZE) 1075 1076 /* No need to store r1/PT_SP as it goes into KSP below */ 1077 l.sw PT_GPR2(r1),r2 1078 l.sw PT_GPR9(r1),r9 1079 /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being 1080 * and expects r12 to be callee-saved... */ 1081 l.sw PT_GPR12(r1),r12 1082 l.sw PT_GPR14(r1),r14 1083 l.sw PT_GPR16(r1),r16 1084 l.sw PT_GPR18(r1),r18 1085 l.sw PT_GPR20(r1),r20 1086 l.sw PT_GPR22(r1),r22 1087 l.sw PT_GPR24(r1),r24 1088 l.sw PT_GPR26(r1),r26 1089 l.sw PT_GPR28(r1),r28 1090 l.sw PT_GPR30(r1),r30 1091 1092 l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ 1093 1094 /* We use thread_info->ksp for storing the address of the above 1095 * structure so that we can get back to it later... we don't want 1096 * to lose the value of thread_info->ksp, though, so store it as 1097 * pt_regs->sp so that we can easily restore it when we are made 1098 * live again... 1099 */ 1100 1101 /* Save the old value of thread_info->ksp as pt_regs->sp */ 1102 l.lwz r29,TI_KSP(r10) 1103 l.sw PT_SP(r1),r29 1104 1105 /* Swap kernel stack pointers */ 1106 l.sw TI_KSP(r10),r1 /* Save old stack pointer */ 1107 l.or r10,r4,r0 /* Set up new current_thread_info */ 1108 l.lwz r1,TI_KSP(r10) /* Load new stack pointer */ 1109 1110 /* Restore the old value of thread_info->ksp */ 1111 l.lwz r29,PT_SP(r1) 1112 l.sw TI_KSP(r10),r29 1113 1114 /* ...and restore the registers, except r11 because the return value 1115 * has already been set above. 1116 */ 1117 l.lwz r2,PT_GPR2(r1) 1118 l.lwz r9,PT_GPR9(r1) 1119 /* No need to restore r10 */ 1120 /* ...and do not restore r11 */ 1121 1122 /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being 1123 * and expects r12 to be callee-saved... */ 1124 l.lwz r12,PT_GPR12(r1) 1125 l.lwz r14,PT_GPR14(r1) 1126 l.lwz r16,PT_GPR16(r1) 1127 l.lwz r18,PT_GPR18(r1) 1128 l.lwz r20,PT_GPR20(r1) 1129 l.lwz r22,PT_GPR22(r1) 1130 l.lwz r24,PT_GPR24(r1) 1131 l.lwz r26,PT_GPR26(r1) 1132 l.lwz r28,PT_GPR28(r1) 1133 l.lwz r30,PT_GPR30(r1) 1134 1135 /* Unwind stack to pre-switch state */ 1136 l.addi r1,r1,(INT_FRAME_SIZE) 1137 1138 /* Return via the link-register back to where we 'came from', where 1139 * that may be either schedule(), ret_from_fork(), or 1140 * ret_from_kernel_thread(). If we are returning to a new thread, 1141 * we are expected to have set up the arg to schedule_tail already, 1142 * hence we do so here unconditionally: 1143 */ 1144 l.lwz r3,TI_TASK(r3) /* Load 'prev' as schedule_tail arg */ 1145 l.jr r9 1146 l.nop 1147 1148/* ==================================================================== */ 1149 1150/* These all use the delay slot for setting the argument register, so the 1151 * jump is always happening after the l.addi instruction. 1152 * 1153 * These are all just wrappers that don't touch the link-register r9, so the 1154 * return from the "real" syscall function will return back to the syscall 1155 * code that did the l.jal that brought us here. 1156 */ 1157 1158/* fork requires that we save all the callee-saved registers because they 1159 * are all effectively clobbered by the call to _switch. Here we store 1160 * all the registers that aren't touched by the syscall fast path and thus 1161 * weren't saved there. 1162 */ 1163 1164_fork_save_extra_regs_and_call: 1165 l.sw PT_GPR14(r1),r14 1166 l.sw PT_GPR16(r1),r16 1167 l.sw PT_GPR18(r1),r18 1168 l.sw PT_GPR20(r1),r20 1169 l.sw PT_GPR22(r1),r22 1170 l.sw PT_GPR24(r1),r24 1171 l.sw PT_GPR26(r1),r26 1172 l.jr r29 1173 l.sw PT_GPR28(r1),r28 1174 1175ENTRY(__sys_clone) 1176 l.movhi r29,hi(sys_clone) 1177 l.ori r29,r29,lo(sys_clone) 1178 l.j _fork_save_extra_regs_and_call 1179 l.addi r7,r1,0 1180 1181ENTRY(__sys_fork) 1182 l.movhi r29,hi(sys_fork) 1183 l.ori r29,r29,lo(sys_fork) 1184 l.j _fork_save_extra_regs_and_call 1185 l.addi r3,r1,0 1186 1187ENTRY(sys_rt_sigreturn) 1188 l.jal _sys_rt_sigreturn 1189 l.addi r3,r1,0 1190 l.sfne r30,r0 1191 l.bnf _no_syscall_trace 1192 l.nop 1193 l.jal do_syscall_trace_leave 1194 l.addi r3,r1,0 1195_no_syscall_trace: 1196 l.j _resume_userspace 1197 l.nop 1198 1199/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000. 1200 * The functions takes a variable number of parameters depending on which 1201 * particular flavour of atomic you want... parameter 1 is a flag identifying 1202 * the atomic in question. Currently, this function implements the 1203 * following variants: 1204 * 1205 * XCHG: 1206 * @flag: 1 1207 * @ptr1: 1208 * @ptr2: 1209 * Atomically exchange the values in pointers 1 and 2. 1210 * 1211 */ 1212 1213ENTRY(sys_or1k_atomic) 1214 /* FIXME: This ignores r3 and always does an XCHG */ 1215 DISABLE_INTERRUPTS(r17,r19) 1216 l.lwz r29,0(r4) 1217 l.lwz r27,0(r5) 1218 l.sw 0(r4),r27 1219 l.sw 0(r5),r29 1220 ENABLE_INTERRUPTS(r17) 1221 l.jr r9 1222 l.or r11,r0,r0 1223 1224/* ============================================================[ EOF ]=== */ 1225