1/* 2 * Low-level system-call handling, trap handlers and context-switching 3 * 4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> 5 * Copyright (C) 2008-2009 PetaLogix 6 * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> 7 * Copyright (C) 2001,2002 NEC Corporation 8 * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org> 9 * 10 * This file is subject to the terms and conditions of the GNU General 11 * Public License. See the file COPYING in the main directory of this 12 * archive for more details. 13 * 14 * Written by Miles Bader <miles@gnu.org> 15 * Heavily modified by John Williams for Microblaze 16 */ 17 18#include <linux/sys.h> 19#include <linux/linkage.h> 20 21#include <asm/entry.h> 22#include <asm/current.h> 23#include <asm/processor.h> 24#include <asm/exceptions.h> 25#include <asm/asm-offsets.h> 26#include <asm/thread_info.h> 27 28#include <asm/page.h> 29#include <asm/unistd.h> 30 31#include <linux/errno.h> 32#include <asm/signal.h> 33 34#undef DEBUG 35 36#ifdef DEBUG 37/* Create space for syscalls counting. */ 38.section .data 39.global syscall_debug_table 40.align 4 41syscall_debug_table: 42 .space (__NR_syscalls * 4) 43#endif /* DEBUG */ 44 45#define C_ENTRY(name) .globl name; .align 4; name 46 47/* 48 * Various ways of setting and clearing BIP in flags reg. 49 * This is mucky, but necessary using microblaze version that 50 * allows msr ops to write to BIP 51 */ 52#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR 53 .macro clear_bip 54 msrclr r0, MSR_BIP 55 .endm 56 57 .macro set_bip 58 msrset r0, MSR_BIP 59 .endm 60 61 .macro clear_eip 62 msrclr r0, MSR_EIP 63 .endm 64 65 .macro set_ee 66 msrset r0, MSR_EE 67 .endm 68 69 .macro disable_irq 70 msrclr r0, MSR_IE 71 .endm 72 73 .macro enable_irq 74 msrset r0, MSR_IE 75 .endm 76 77 .macro set_ums 78 msrset r0, MSR_UMS 79 msrclr r0, MSR_VMS 80 .endm 81 82 .macro set_vms 83 msrclr r0, MSR_UMS 84 msrset r0, MSR_VMS 85 .endm 86 87 .macro clear_ums 88 msrclr r0, MSR_UMS 89 .endm 90 91 .macro clear_vms_ums 92 msrclr r0, MSR_VMS | MSR_UMS 93 .endm 94#else 95 .macro clear_bip 96 mfs r11, rmsr 97 andi r11, r11, ~MSR_BIP 98 mts rmsr, r11 99 .endm 100 101 .macro set_bip 102 mfs r11, rmsr 103 ori r11, r11, MSR_BIP 104 mts rmsr, r11 105 .endm 106 107 .macro clear_eip 108 mfs r11, rmsr 109 andi r11, r11, ~MSR_EIP 110 mts rmsr, r11 111 .endm 112 113 .macro set_ee 114 mfs r11, rmsr 115 ori r11, r11, MSR_EE 116 mts rmsr, r11 117 .endm 118 119 .macro disable_irq 120 mfs r11, rmsr 121 andi r11, r11, ~MSR_IE 122 mts rmsr, r11 123 .endm 124 125 .macro enable_irq 126 mfs r11, rmsr 127 ori r11, r11, MSR_IE 128 mts rmsr, r11 129 .endm 130 131 .macro set_ums 132 mfs r11, rmsr 133 ori r11, r11, MSR_VMS 134 andni r11, r11, MSR_UMS 135 mts rmsr, r11 136 .endm 137 138 .macro set_vms 139 mfs r11, rmsr 140 ori r11, r11, MSR_VMS 141 andni r11, r11, MSR_UMS 142 mts rmsr, r11 143 .endm 144 145 .macro clear_ums 146 mfs r11, rmsr 147 andni r11, r11, MSR_UMS 148 mts rmsr,r11 149 .endm 150 151 .macro clear_vms_ums 152 mfs r11, rmsr 153 andni r11, r11, (MSR_VMS|MSR_UMS) 154 mts rmsr,r11 155 .endm 156#endif 157 158/* Define how to call high-level functions. With MMU, virtual mode must be 159 * enabled when calling the high-level function. Clobbers R11. 160 * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL 161 */ 162 163/* turn on virtual protected mode save */ 164#define VM_ON \ 165 set_ums; \ 166 rted r0, 2f; \ 167 nop; \ 1682: 169 170/* turn off virtual protected mode save and user mode save*/ 171#define VM_OFF \ 172 clear_vms_ums; \ 173 rted r0, TOPHYS(1f); \ 174 nop; \ 1751: 176 177#define SAVE_REGS \ 178 swi r2, r1, PT_R2; /* Save SDA */ \ 179 swi r3, r1, PT_R3; \ 180 swi r4, r1, PT_R4; \ 181 swi r5, r1, PT_R5; \ 182 swi r6, r1, PT_R6; \ 183 swi r7, r1, PT_R7; \ 184 swi r8, r1, PT_R8; \ 185 swi r9, r1, PT_R9; \ 186 swi r10, r1, PT_R10; \ 187 swi r11, r1, PT_R11; /* save clobbered regs after rval */\ 188 swi r12, r1, PT_R12; \ 189 swi r13, r1, PT_R13; /* Save SDA2 */ \ 190 swi r14, r1, PT_PC; /* PC, before IRQ/trap */ \ 191 swi r15, r1, PT_R15; /* Save LP */ \ 192 swi r16, r1, PT_R16; \ 193 swi r17, r1, PT_R17; \ 194 swi r18, r1, PT_R18; /* Save asm scratch reg */ \ 195 swi r19, r1, PT_R19; \ 196 swi r20, r1, PT_R20; \ 197 swi r21, r1, PT_R21; \ 198 swi r22, r1, PT_R22; \ 199 swi r23, r1, PT_R23; \ 200 swi r24, r1, PT_R24; \ 201 swi r25, r1, PT_R25; \ 202 swi r26, r1, PT_R26; \ 203 swi r27, r1, PT_R27; \ 204 swi r28, r1, PT_R28; \ 205 swi r29, r1, PT_R29; \ 206 swi r30, r1, PT_R30; \ 207 swi r31, r1, PT_R31; /* Save current task reg */ \ 208 mfs r11, rmsr; /* save MSR */ \ 209 swi r11, r1, PT_MSR; 210 211#define RESTORE_REGS_GP \ 212 lwi r2, r1, PT_R2; /* restore SDA */ \ 213 lwi r3, r1, PT_R3; \ 214 lwi r4, r1, PT_R4; \ 215 lwi r5, r1, PT_R5; \ 216 lwi r6, r1, PT_R6; \ 217 lwi r7, r1, PT_R7; \ 218 lwi r8, r1, PT_R8; \ 219 lwi r9, r1, PT_R9; \ 220 lwi r10, r1, PT_R10; \ 221 lwi r11, r1, PT_R11; /* restore clobbered regs after rval */\ 222 lwi r12, r1, PT_R12; \ 223 lwi r13, r1, PT_R13; /* restore SDA2 */ \ 224 lwi r14, r1, PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\ 225 lwi r15, r1, PT_R15; /* restore LP */ \ 226 lwi r16, r1, PT_R16; \ 227 lwi r17, r1, PT_R17; \ 228 lwi r18, r1, PT_R18; /* restore asm scratch reg */ \ 229 lwi r19, r1, PT_R19; \ 230 lwi r20, r1, PT_R20; \ 231 lwi r21, r1, PT_R21; \ 232 lwi r22, r1, PT_R22; \ 233 lwi r23, r1, PT_R23; \ 234 lwi r24, r1, PT_R24; \ 235 lwi r25, r1, PT_R25; \ 236 lwi r26, r1, PT_R26; \ 237 lwi r27, r1, PT_R27; \ 238 lwi r28, r1, PT_R28; \ 239 lwi r29, r1, PT_R29; \ 240 lwi r30, r1, PT_R30; \ 241 lwi r31, r1, PT_R31; /* Restore cur task reg */ 242 243#define RESTORE_REGS \ 244 lwi r11, r1, PT_MSR; \ 245 mts rmsr , r11; \ 246 RESTORE_REGS_GP 247 248#define RESTORE_REGS_RTBD \ 249 lwi r11, r1, PT_MSR; \ 250 andni r11, r11, MSR_EIP; /* clear EIP */ \ 251 ori r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */ \ 252 mts rmsr , r11; \ 253 RESTORE_REGS_GP 254 255#define SAVE_STATE \ 256 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ 257 /* See if already in kernel mode.*/ \ 258 mfs r1, rmsr; \ 259 andi r1, r1, MSR_UMS; \ 260 bnei r1, 1f; \ 261 /* Kernel-mode state save. */ \ 262 /* Reload kernel stack-ptr. */ \ 263 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ 264 /* FIXME: I can add these two lines to one */ \ 265 /* tophys(r1,r1); */ \ 266 /* addik r1, r1, -PT_SIZE; */ \ 267 addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ 268 SAVE_REGS \ 269 brid 2f; \ 270 swi r1, r1, PT_MODE; \ 2711: /* User-mode state save. */ \ 272 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ 273 tophys(r1,r1); \ 274 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ 275 /* MS these three instructions can be added to one */ \ 276 /* addik r1, r1, THREAD_SIZE; */ \ 277 /* tophys(r1,r1); */ \ 278 /* addik r1, r1, -PT_SIZE; */ \ 279 addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ 280 SAVE_REGS \ 281 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ 282 swi r11, r1, PT_R1; /* Store user SP. */ \ 283 swi r0, r1, PT_MODE; /* Was in user-mode. */ \ 284 /* MS: I am clearing UMS even in case when I come from kernel space */ \ 285 clear_ums; \ 2862: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 287 288.text 289 290/* 291 * User trap. 292 * 293 * System calls are handled here. 294 * 295 * Syscall protocol: 296 * Syscall number in r12, args in r5-r10 297 * Return value in r3 298 * 299 * Trap entered via brki instruction, so BIP bit is set, and interrupts 300 * are masked. This is nice, means we don't have to CLI before state save 301 */ 302C_ENTRY(_user_exception): 303 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ 304 addi r14, r14, 4 /* return address is 4 byte after call */ 305 306 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ 307 tophys(r1,r1); 308 lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ 309/* calculate kernel stack pointer from task struct 8k */ 310 addik r1, r1, THREAD_SIZE; 311 tophys(r1,r1); 312 313 addik r1, r1, -PT_SIZE; /* Make room on the stack. */ 314 SAVE_REGS 315 swi r0, r1, PT_R3 316 swi r0, r1, PT_R4 317 318 swi r0, r1, PT_MODE; /* Was in user-mode. */ 319 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 320 swi r11, r1, PT_R1; /* Store user SP. */ 321 clear_ums; 3222: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 323 /* Save away the syscall number. */ 324 swi r12, r1, PT_R0; 325 tovirt(r1,r1) 326 327/* where the trap should return need -8 to adjust for rtsd r15, 8*/ 328/* Jump to the appropriate function for the system call number in r12 329 * (r12 is not preserved), or return an error if r12 is not valid. The LP 330 * register should point to the location where 331 * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ 332 333 /* Step into virtual mode */ 334 rtbd r0, 3f 335 nop 3363: 337 lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */ 338 lwi r11, r11, TI_FLAGS /* get flags in thread info */ 339 andi r11, r11, _TIF_WORK_SYSCALL_MASK 340 beqi r11, 4f 341 342 addik r3, r0, -ENOSYS 343 swi r3, r1, PT_R3 344 brlid r15, do_syscall_trace_enter 345 addik r5, r1, PT_R0 346 347 # do_syscall_trace_enter returns the new syscall nr. 348 addk r12, r0, r3 349 lwi r5, r1, PT_R5; 350 lwi r6, r1, PT_R6; 351 lwi r7, r1, PT_R7; 352 lwi r8, r1, PT_R8; 353 lwi r9, r1, PT_R9; 354 lwi r10, r1, PT_R10; 3554: 356/* Jump to the appropriate function for the system call number in r12 357 * (r12 is not preserved), or return an error if r12 is not valid. 358 * The LP register should point to the location where the called function 359 * should return. [note that MAKE_SYS_CALL uses label 1] */ 360 /* See if the system call number is valid */ 361 blti r12, 5f 362 addi r11, r12, -__NR_syscalls; 363 bgei r11, 5f; 364 /* Figure out which function to use for this system call. */ 365 /* Note Microblaze barrel shift is optional, so don't rely on it */ 366 add r12, r12, r12; /* convert num -> ptr */ 367 add r12, r12, r12; 368 addi r30, r0, 1 /* restarts allowed */ 369 370#ifdef DEBUG 371 /* Trac syscalls and stored them to syscall_debug_table */ 372 /* The first syscall location stores total syscall number */ 373 lwi r3, r0, syscall_debug_table 374 addi r3, r3, 1 375 swi r3, r0, syscall_debug_table 376 lwi r3, r12, syscall_debug_table 377 addi r3, r3, 1 378 swi r3, r12, syscall_debug_table 379#endif 380 381 # Find and jump into the syscall handler. 382 lwi r12, r12, sys_call_table 383 /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 384 addi r15, r0, ret_from_trap-8 385 bra r12 386 387 /* The syscall number is invalid, return an error. */ 3885: 389 braid ret_from_trap 390 addi r3, r0, -ENOSYS; 391 392/* Entry point used to return from a syscall/trap */ 393/* We re-enable BIP bit before state restore */ 394C_ENTRY(ret_from_trap): 395 swi r3, r1, PT_R3 396 swi r4, r1, PT_R4 397 398 lwi r11, r1, PT_MODE; 399/* See if returning to kernel mode, if so, skip resched &c. */ 400 bnei r11, 2f; 401 /* We're returning to user mode, so check for various conditions that 402 * trigger rescheduling. */ 403 /* FIXME: Restructure all these flag checks. */ 404 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 405 lwi r11, r11, TI_FLAGS; /* get flags in thread info */ 406 andi r11, r11, _TIF_WORK_SYSCALL_MASK 407 beqi r11, 1f 408 409 brlid r15, do_syscall_trace_leave 410 addik r5, r1, PT_R0 4111: 412 /* We're returning to user mode, so check for various conditions that 413 * trigger rescheduling. */ 414 /* get thread info from current task */ 415 lwi r11, CURRENT_TASK, TS_THREAD_INFO; 416 lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 417 andi r11, r19, _TIF_NEED_RESCHED; 418 beqi r11, 5f; 419 420 bralid r15, schedule; /* Call scheduler */ 421 nop; /* delay slot */ 422 bri 1b 423 424 /* Maybe handle a signal */ 4255: 426 andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 427 beqi r11, 4f; /* Signals to handle, handle them */ 428 429 addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 430 bralid r15, do_notify_resume; /* Handle any signals */ 431 add r6, r30, r0; /* Arg 2: int in_syscall */ 432 add r30, r0, r0 /* no more restarts */ 433 bri 1b 434 435/* Finally, return to user state. */ 4364: set_bip; /* Ints masked for state restore */ 437 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 438 VM_OFF; 439 tophys(r1,r1); 440 RESTORE_REGS_RTBD; 441 addik r1, r1, PT_SIZE /* Clean up stack space. */ 442 lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ 443 bri 6f; 444 445/* Return to kernel state. */ 4462: set_bip; /* Ints masked for state restore */ 447 VM_OFF; 448 tophys(r1,r1); 449 RESTORE_REGS_RTBD; 450 addik r1, r1, PT_SIZE /* Clean up stack space. */ 451 tovirt(r1,r1); 4526: 453TRAP_return: /* Make global symbol for debugging */ 454 rtbd r14, 0; /* Instructions to return from an IRQ */ 455 nop; 456 457 458/* This the initial entry point for a new child thread, with an appropriate 459 stack in place that makes it look the the child is in the middle of an 460 syscall. This function is actually `returned to' from switch_thread 461 (copy_thread makes ret_from_fork the return address in each new thread's 462 saved context). */ 463C_ENTRY(ret_from_fork): 464 bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ 465 add r5, r3, r0; /* switch_thread returns the prev task */ 466 /* ( in the delay slot ) */ 467 brid ret_from_trap; /* Do normal trap return */ 468 add r3, r0, r0; /* Child's fork call should return 0. */ 469 470C_ENTRY(ret_from_kernel_thread): 471 bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ 472 add r5, r3, r0; /* switch_thread returns the prev task */ 473 /* ( in the delay slot ) */ 474 brald r15, r20 /* fn was left in r20 */ 475 addk r5, r0, r19 /* ... and argument - in r19 */ 476 brid ret_from_trap 477 add r3, r0, r0 478 479C_ENTRY(sys_rt_sigreturn_wrapper): 480 addik r30, r0, 0 /* no restarts */ 481 brid sys_rt_sigreturn /* Do real work */ 482 addik r5, r1, 0; /* add user context as 1st arg */ 483 484/* 485 * HW EXCEPTION rutine start 486 */ 487C_ENTRY(full_exception_trap): 488 /* adjust exception address for privileged instruction 489 * for finding where is it */ 490 addik r17, r17, -4 491 SAVE_STATE /* Save registers */ 492 /* PC, before IRQ/trap - this is one instruction above */ 493 swi r17, r1, PT_PC; 494 tovirt(r1,r1) 495 /* FIXME this can be store directly in PT_ESR reg. 496 * I tested it but there is a fault */ 497 /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 498 addik r15, r0, ret_from_exc - 8 499 mfs r6, resr 500 mfs r7, rfsr; /* save FSR */ 501 mts rfsr, r0; /* Clear sticky fsr */ 502 rted r0, full_exception 503 addik r5, r1, 0 /* parameter struct pt_regs * regs */ 504 505/* 506 * Unaligned data trap. 507 * 508 * Unaligned data trap last on 4k page is handled here. 509 * 510 * Trap entered via exception, so EE bit is set, and interrupts 511 * are masked. This is nice, means we don't have to CLI before state save 512 * 513 * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S" 514 */ 515C_ENTRY(unaligned_data_trap): 516 /* MS: I have to save r11 value and then restore it because 517 * set_bit, clear_eip, set_ee use r11 as temp register if MSR 518 * instructions are not used. We don't need to do if MSR instructions 519 * are used and they use r0 instead of r11. 520 * I am using ENTRY_SP which should be primary used only for stack 521 * pointer saving. */ 522 swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 523 set_bip; /* equalize initial state for all possible entries */ 524 clear_eip; 525 set_ee; 526 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 527 SAVE_STATE /* Save registers.*/ 528 /* PC, before IRQ/trap - this is one instruction above */ 529 swi r17, r1, PT_PC; 530 tovirt(r1,r1) 531 /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 532 addik r15, r0, ret_from_exc-8 533 mfs r3, resr /* ESR */ 534 mfs r4, rear /* EAR */ 535 rtbd r0, _unaligned_data_exception 536 addik r7, r1, 0 /* parameter struct pt_regs * regs */ 537 538/* 539 * Page fault traps. 540 * 541 * If the real exception handler (from hw_exception_handler.S) didn't find 542 * the mapping for the process, then we're thrown here to handle such situation. 543 * 544 * Trap entered via exceptions, so EE bit is set, and interrupts 545 * are masked. This is nice, means we don't have to CLI before state save 546 * 547 * Build a standard exception frame for TLB Access errors. All TLB exceptions 548 * will bail out to this point if they can't resolve the lightweight TLB fault. 549 * 550 * The C function called is in "arch/microblaze/mm/fault.c", declared as: 551 * void do_page_fault(struct pt_regs *regs, 552 * unsigned long address, 553 * unsigned long error_code) 554 */ 555/* data and intruction trap - which is choose is resolved int fault.c */ 556C_ENTRY(page_fault_data_trap): 557 SAVE_STATE /* Save registers.*/ 558 /* PC, before IRQ/trap - this is one instruction above */ 559 swi r17, r1, PT_PC; 560 tovirt(r1,r1) 561 /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 562 addik r15, r0, ret_from_exc-8 563 mfs r6, rear /* parameter unsigned long address */ 564 mfs r7, resr /* parameter unsigned long error_code */ 565 rted r0, do_page_fault 566 addik r5, r1, 0 /* parameter struct pt_regs * regs */ 567 568C_ENTRY(page_fault_instr_trap): 569 SAVE_STATE /* Save registers.*/ 570 /* PC, before IRQ/trap - this is one instruction above */ 571 swi r17, r1, PT_PC; 572 tovirt(r1,r1) 573 /* where the trap should return need -8 to adjust for rtsd r15, 8 */ 574 addik r15, r0, ret_from_exc-8 575 mfs r6, rear /* parameter unsigned long address */ 576 ori r7, r0, 0 /* parameter unsigned long error_code */ 577 rted r0, do_page_fault 578 addik r5, r1, 0 /* parameter struct pt_regs * regs */ 579 580/* Entry point used to return from an exception. */ 581C_ENTRY(ret_from_exc): 582 lwi r11, r1, PT_MODE; 583 bnei r11, 2f; /* See if returning to kernel mode, */ 584 /* ... if so, skip resched &c. */ 585 586 /* We're returning to user mode, so check for various conditions that 587 trigger rescheduling. */ 5881: 589 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 590 lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 591 andi r11, r19, _TIF_NEED_RESCHED; 592 beqi r11, 5f; 593 594/* Call the scheduler before returning from a syscall/trap. */ 595 bralid r15, schedule; /* Call scheduler */ 596 nop; /* delay slot */ 597 bri 1b 598 599 /* Maybe handle a signal */ 6005: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 601 beqi r11, 4f; /* Signals to handle, handle them */ 602 603 /* 604 * Handle a signal return; Pending signals should be in r18. 605 * 606 * Not all registers are saved by the normal trap/interrupt entry 607 * points (for instance, call-saved registers (because the normal 608 * C-compiler calling sequence in the kernel makes sure they're 609 * preserved), and call-clobbered registers in the case of 610 * traps), but signal handlers may want to examine or change the 611 * complete register state. Here we save anything not saved by 612 * the normal entry sequence, so that it may be safely restored 613 * (in a possibly modified form) after do_notify_resume returns. */ 614 addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 615 bralid r15, do_notify_resume; /* Handle any signals */ 616 addi r6, r0, 0; /* Arg 2: int in_syscall */ 617 bri 1b 618 619/* Finally, return to user state. */ 6204: set_bip; /* Ints masked for state restore */ 621 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 622 VM_OFF; 623 tophys(r1,r1); 624 625 RESTORE_REGS_RTBD; 626 addik r1, r1, PT_SIZE /* Clean up stack space. */ 627 628 lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */ 629 bri 6f; 630/* Return to kernel state. */ 6312: set_bip; /* Ints masked for state restore */ 632 VM_OFF; 633 tophys(r1,r1); 634 RESTORE_REGS_RTBD; 635 addik r1, r1, PT_SIZE /* Clean up stack space. */ 636 637 tovirt(r1,r1); 6386: 639EXC_return: /* Make global symbol for debugging */ 640 rtbd r14, 0; /* Instructions to return from an IRQ */ 641 nop; 642 643/* 644 * HW EXCEPTION rutine end 645 */ 646 647/* 648 * Hardware maskable interrupts. 649 * 650 * The stack-pointer (r1) should have already been saved to the memory 651 * location PER_CPU(ENTRY_SP). 652 */ 653C_ENTRY(_interrupt): 654/* MS: we are in physical address */ 655/* Save registers, switch to proper stack, convert SP to virtual.*/ 656 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 657 /* MS: See if already in kernel mode. */ 658 mfs r1, rmsr 659 nop 660 andi r1, r1, MSR_UMS 661 bnei r1, 1f 662 663/* Kernel-mode state save. */ 664 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 665 tophys(r1,r1); /* MS: I have in r1 physical address where stack is */ 666 /* save registers */ 667/* MS: Make room on the stack -> activation record */ 668 addik r1, r1, -PT_SIZE; 669 SAVE_REGS 670 brid 2f; 671 swi r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */ 6721: 673/* User-mode state save. */ 674 /* MS: get the saved current */ 675 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 676 tophys(r1,r1); 677 lwi r1, r1, TS_THREAD_INFO; 678 addik r1, r1, THREAD_SIZE; 679 tophys(r1,r1); 680 /* save registers */ 681 addik r1, r1, -PT_SIZE; 682 SAVE_REGS 683 /* calculate mode */ 684 swi r0, r1, PT_MODE; 685 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 686 swi r11, r1, PT_R1; 687 clear_ums; 6882: 689 lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 690 tovirt(r1,r1) 691 addik r15, r0, irq_call; 692irq_call:rtbd r0, do_IRQ; 693 addik r5, r1, 0; 694 695/* MS: we are in virtual mode */ 696ret_from_irq: 697 lwi r11, r1, PT_MODE; 698 bnei r11, 2f; 699 7001: 701 lwi r11, CURRENT_TASK, TS_THREAD_INFO; 702 lwi r19, r11, TI_FLAGS; /* MS: get flags from thread info */ 703 andi r11, r19, _TIF_NEED_RESCHED; 704 beqi r11, 5f 705 bralid r15, schedule; 706 nop; /* delay slot */ 707 bri 1b 708 709 /* Maybe handle a signal */ 7105: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 711 beqid r11, no_intr_resched 712/* Handle a signal return; Pending signals should be in r18. */ 713 addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 714 bralid r15, do_notify_resume; /* Handle any signals */ 715 addi r6, r0, 0; /* Arg 2: int in_syscall */ 716 bri 1b 717 718/* Finally, return to user state. */ 719no_intr_resched: 720 /* Disable interrupts, we are now committed to the state restore */ 721 disable_irq 722 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); 723 VM_OFF; 724 tophys(r1,r1); 725 RESTORE_REGS 726 addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ 727 lwi r1, r1, PT_R1 - PT_SIZE; 728 bri 6f; 729/* MS: Return to kernel state. */ 7302: 731#ifdef CONFIG_PREEMPT 732 lwi r11, CURRENT_TASK, TS_THREAD_INFO; 733 /* MS: get preempt_count from thread info */ 734 lwi r5, r11, TI_PREEMPT_COUNT; 735 bgti r5, restore; 736 737 lwi r5, r11, TI_FLAGS; /* get flags in thread info */ 738 andi r5, r5, _TIF_NEED_RESCHED; 739 beqi r5, restore /* if zero jump over */ 740 741preempt: 742 /* interrupts are off that's why I am calling preempt_chedule_irq */ 743 bralid r15, preempt_schedule_irq 744 nop 745 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 746 lwi r5, r11, TI_FLAGS; /* get flags in thread info */ 747 andi r5, r5, _TIF_NEED_RESCHED; 748 bnei r5, preempt /* if non zero jump to resched */ 749restore: 750#endif 751 VM_OFF /* MS: turn off MMU */ 752 tophys(r1,r1) 753 RESTORE_REGS 754 addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ 755 tovirt(r1,r1); 7566: 757IRQ_return: /* MS: Make global symbol for debugging */ 758 rtid r14, 0 759 nop 760 761/* 762 * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18 763 * and call handling function with saved pt_regs 764 */ 765C_ENTRY(_debug_exception): 766 /* BIP bit is set on entry, no interrupts can occur */ 767 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) 768 769 mfs r1, rmsr 770 nop 771 andi r1, r1, MSR_UMS 772 bnei r1, 1f 773/* MS: Kernel-mode state save - kgdb */ 774 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ 775 776 /* BIP bit is set on entry, no interrupts can occur */ 777 addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; 778 SAVE_REGS; 779 /* save all regs to pt_reg structure */ 780 swi r0, r1, PT_R0; /* R0 must be saved too */ 781 swi r14, r1, PT_R14 /* rewrite saved R14 value */ 782 swi r16, r1, PT_PC; /* PC and r16 are the same */ 783 /* save special purpose registers to pt_regs */ 784 mfs r11, rear; 785 swi r11, r1, PT_EAR; 786 mfs r11, resr; 787 swi r11, r1, PT_ESR; 788 mfs r11, rfsr; 789 swi r11, r1, PT_FSR; 790 791 /* stack pointer is in physical address at it is decrease 792 * by PT_SIZE but we need to get correct R1 value */ 793 addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE; 794 swi r11, r1, PT_R1 795 /* MS: r31 - current pointer isn't changed */ 796 tovirt(r1,r1) 797#ifdef CONFIG_KGDB 798 addi r5, r1, 0 /* pass pt_reg address as the first arg */ 799 addik r15, r0, dbtrap_call; /* return address */ 800 rtbd r0, microblaze_kgdb_break 801 nop; 802#endif 803 /* MS: Place handler for brki from kernel space if KGDB is OFF. 804 * It is very unlikely that another brki instruction is called. */ 805 bri 0 806 807/* MS: User-mode state save - gdb */ 8081: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ 809 tophys(r1,r1); 810 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ 811 addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ 812 tophys(r1,r1); 813 814 addik r1, r1, -PT_SIZE; /* Make room on the stack. */ 815 SAVE_REGS; 816 swi r16, r1, PT_PC; /* Save LP */ 817 swi r0, r1, PT_MODE; /* Was in user-mode. */ 818 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); 819 swi r11, r1, PT_R1; /* Store user SP. */ 820 lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 821 tovirt(r1,r1) 822 set_vms; 823 addik r5, r1, 0; 824 addik r15, r0, dbtrap_call; 825dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ 826 rtbd r0, sw_exception 827 nop 828 829 /* MS: The first instruction for the second part of the gdb/kgdb */ 830 set_bip; /* Ints masked for state restore */ 831 lwi r11, r1, PT_MODE; 832 bnei r11, 2f; 833/* MS: Return to user space - gdb */ 8341: 835 /* Get current task ptr into r11 */ 836 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ 837 lwi r19, r11, TI_FLAGS; /* get flags in thread info */ 838 andi r11, r19, _TIF_NEED_RESCHED; 839 beqi r11, 5f; 840 841 /* Call the scheduler before returning from a syscall/trap. */ 842 bralid r15, schedule; /* Call scheduler */ 843 nop; /* delay slot */ 844 bri 1b 845 846 /* Maybe handle a signal */ 8475: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; 848 beqi r11, 4f; /* Signals to handle, handle them */ 849 850 addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ 851 bralid r15, do_notify_resume; /* Handle any signals */ 852 addi r6, r0, 0; /* Arg 2: int in_syscall */ 853 bri 1b 854 855/* Finally, return to user state. */ 8564: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ 857 VM_OFF; 858 tophys(r1,r1); 859 /* MS: Restore all regs */ 860 RESTORE_REGS_RTBD 861 addik r1, r1, PT_SIZE /* Clean up stack space */ 862 lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */ 863DBTRAP_return_user: /* MS: Make global symbol for debugging */ 864 rtbd r16, 0; /* MS: Instructions to return from a debug trap */ 865 nop; 866 867/* MS: Return to kernel state - kgdb */ 8682: VM_OFF; 869 tophys(r1,r1); 870 /* MS: Restore all regs */ 871 RESTORE_REGS_RTBD 872 lwi r14, r1, PT_R14; 873 lwi r16, r1, PT_PC; 874 addik r1, r1, PT_SIZE; /* MS: Clean up stack space */ 875 tovirt(r1,r1); 876DBTRAP_return_kernel: /* MS: Make global symbol for debugging */ 877 rtbd r16, 0; /* MS: Instructions to return from a debug trap */ 878 nop; 879 880 881ENTRY(_switch_to) 882 /* prepare return value */ 883 addk r3, r0, CURRENT_TASK 884 885 /* save registers in cpu_context */ 886 /* use r11 and r12, volatile registers, as temp register */ 887 /* give start of cpu_context for previous process */ 888 addik r11, r5, TI_CPU_CONTEXT 889 swi r1, r11, CC_R1 890 swi r2, r11, CC_R2 891 /* skip volatile registers. 892 * they are saved on stack when we jumped to _switch_to() */ 893 /* dedicated registers */ 894 swi r13, r11, CC_R13 895 swi r14, r11, CC_R14 896 swi r15, r11, CC_R15 897 swi r16, r11, CC_R16 898 swi r17, r11, CC_R17 899 swi r18, r11, CC_R18 900 /* save non-volatile registers */ 901 swi r19, r11, CC_R19 902 swi r20, r11, CC_R20 903 swi r21, r11, CC_R21 904 swi r22, r11, CC_R22 905 swi r23, r11, CC_R23 906 swi r24, r11, CC_R24 907 swi r25, r11, CC_R25 908 swi r26, r11, CC_R26 909 swi r27, r11, CC_R27 910 swi r28, r11, CC_R28 911 swi r29, r11, CC_R29 912 swi r30, r11, CC_R30 913 /* special purpose registers */ 914 mfs r12, rmsr 915 swi r12, r11, CC_MSR 916 mfs r12, rear 917 swi r12, r11, CC_EAR 918 mfs r12, resr 919 swi r12, r11, CC_ESR 920 mfs r12, rfsr 921 swi r12, r11, CC_FSR 922 923 /* update r31, the current-give me pointer to task which will be next */ 924 lwi CURRENT_TASK, r6, TI_TASK 925 /* stored it to current_save too */ 926 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE) 927 928 /* get new process' cpu context and restore */ 929 /* give me start where start context of next task */ 930 addik r11, r6, TI_CPU_CONTEXT 931 932 /* non-volatile registers */ 933 lwi r30, r11, CC_R30 934 lwi r29, r11, CC_R29 935 lwi r28, r11, CC_R28 936 lwi r27, r11, CC_R27 937 lwi r26, r11, CC_R26 938 lwi r25, r11, CC_R25 939 lwi r24, r11, CC_R24 940 lwi r23, r11, CC_R23 941 lwi r22, r11, CC_R22 942 lwi r21, r11, CC_R21 943 lwi r20, r11, CC_R20 944 lwi r19, r11, CC_R19 945 /* dedicated registers */ 946 lwi r18, r11, CC_R18 947 lwi r17, r11, CC_R17 948 lwi r16, r11, CC_R16 949 lwi r15, r11, CC_R15 950 lwi r14, r11, CC_R14 951 lwi r13, r11, CC_R13 952 /* skip volatile registers */ 953 lwi r2, r11, CC_R2 954 lwi r1, r11, CC_R1 955 956 /* special purpose registers */ 957 lwi r12, r11, CC_FSR 958 mts rfsr, r12 959 lwi r12, r11, CC_MSR 960 mts rmsr, r12 961 962 rtsd r15, 8 963 nop 964 965ENTRY(_reset) 966 brai 0; /* Jump to reset vector */ 967 968 /* These are compiled and loaded into high memory, then 969 * copied into place in mach_early_setup */ 970 .section .init.ivt, "ax" 971#if CONFIG_MANUAL_RESET_VECTOR 972 .org 0x0 973 brai CONFIG_MANUAL_RESET_VECTOR 974#endif 975 .org 0x8 976 brai TOPHYS(_user_exception); /* syscall handler */ 977 .org 0x10 978 brai TOPHYS(_interrupt); /* Interrupt handler */ 979 .org 0x18 980 brai TOPHYS(_debug_exception); /* debug trap handler */ 981 .org 0x20 982 brai TOPHYS(_hw_exception_handler); /* HW exception handler */ 983 984.section .rodata,"a" 985#include "syscall_table.S" 986 987syscall_table_size=(.-sys_call_table) 988 989type_SYSCALL: 990 .ascii "SYSCALL\0" 991type_IRQ: 992 .ascii "IRQ\0" 993type_IRQ_PREEMPT: 994 .ascii "IRQ (PREEMPTED)\0" 995type_SYSCALL_PREEMPT: 996 .ascii " SYSCALL (PREEMPTED)\0" 997 998 /* 999 * Trap decoding for stack unwinder 1000 * Tuples are (start addr, end addr, string) 1001 * If return address lies on [start addr, end addr], 1002 * unwinder displays 'string' 1003 */ 1004 1005 .align 4 1006.global microblaze_trap_handlers 1007microblaze_trap_handlers: 1008 /* Exact matches come first */ 1009 .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL 1010 .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ 1011 /* Fuzzy matches go here */ 1012 .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT 1013 .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT 1014 /* End of table */ 1015 .word 0 ; .word 0 ; .word 0 1016