1/* 2 * arch/score/kernel/entry.S 3 * 4 * Score Processor version. 5 * 6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd. 7 * Chen Liqin <liqin.chen@sunplusct.com> 8 * Lennox Wu <lennox.wu@sunplusct.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, see the file COPYING, or write 22 * to the Free Software Foundation, Inc., 23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 */ 25 26#include <linux/err.h> 27#include <linux/init.h> 28#include <linux/linkage.h> 29 30#include <asm/asmmacro.h> 31#include <asm/thread_info.h> 32#include <asm/unistd.h> 33 34/* 35 * disable interrupts. 36 */ 37.macro disable_irq 38 mfcr r8, cr0 39 srli r8, r8, 1 40 slli r8, r8, 1 41 mtcr r8, cr0 42 nop 43 nop 44 nop 45 nop 46 nop 47.endm 48 49/* 50 * enable interrupts. 51 */ 52.macro enable_irq 53 mfcr r8, cr0 54 ori r8, 1 55 mtcr r8, cr0 56 nop 57 nop 58 nop 59 nop 60 nop 61.endm 62 63__INIT 64ENTRY(debug_exception_vector) 65 nop! 66 nop! 67 nop! 68 nop! 69 nop! 70 nop! 71 nop! 72 nop! 73 74ENTRY(general_exception_vector) # should move to addr 0x200 75 j general_exception 76 nop! 77 nop! 78 nop! 79 nop! 80 nop! 81 nop! 82 83ENTRY(interrupt_exception_vector) # should move to addr 0x210 84 j interrupt_exception 85 nop! 86 nop! 87 nop! 88 nop! 89 nop! 90 nop! 91 92 .section ".text", "ax" 93 .align 2; 94general_exception: 95 mfcr r31, cr2 96 nop 97 la r30, exception_handlers 98 andi r31, 0x1f # get ecr.exc_code 99 slli r31, r31, 2 100 add r30, r30, r31 101 lw r30, [r30] 102 br r30 103 104interrupt_exception: 105 SAVE_ALL 106 mfcr r4, cr2 107 nop 108 lw r16, [r28, TI_REGS] 109 sw r0, [r28, TI_REGS] 110 la r3, ret_from_irq 111 srli r4, r4, 18 # get ecr.ip[7:2], interrupt No. 112 mv r5, r0 113 j do_IRQ 114 115ENTRY(handle_nmi) # NMI #1 116 SAVE_ALL 117 mv r4, r0 118 la r8, nmi_exception_handler 119 brl r8 120 j restore_all 121 122ENTRY(handle_adelinsn) # AdEL-instruction #2 123 SAVE_ALL 124 mfcr r8, cr6 125 nop 126 nop 127 sw r8, [r0, PT_EMA] 128 mv r4, r0 129 la r8, do_adelinsn 130 brl r8 131 mv r4, r0 132 j ret_from_exception 133 nop 134 135ENTRY(handle_ibe) # BusEL-instruction #5 136 SAVE_ALL 137 mv r4, r0 138 la r8, do_be 139 brl r8 140 mv r4, r0 141 j ret_from_exception 142 nop 143 144ENTRY(handle_pel) # P-EL #6 145 SAVE_ALL 146 mv r4, r0 147 la r8, do_pel 148 brl r8 149 mv r4, r0 150 j ret_from_exception 151 nop 152 153ENTRY(handle_ccu) # CCU #8 154 SAVE_ALL 155 mv r4, r0 156 la r8, do_ccu 157 brl r8 158 mv r4, r0 159 j ret_from_exception 160 nop 161 162ENTRY(handle_ri) # RI #9 163 SAVE_ALL 164 mv r4, r0 165 la r8, do_ri 166 brl r8 167 mv r4, r0 168 j ret_from_exception 169 nop 170 171ENTRY(handle_tr) # Trap #10 172 SAVE_ALL 173 mv r4, r0 174 la r8, do_tr 175 brl r8 176 mv r4, r0 177 j ret_from_exception 178 nop 179 180ENTRY(handle_adedata) # AdES-instruction #12 181 SAVE_ALL 182 mfcr r8, cr6 183 nop 184 nop 185 sw r8, [r0, PT_EMA] 186 mv r4, r0 187 la r8, do_adedata 188 brl r8 189 mv r4, r0 190 j ret_from_exception 191 nop 192 193ENTRY(handle_cee) # CeE #16 194 SAVE_ALL 195 mv r4, r0 196 la r8, do_cee 197 brl r8 198 mv r4, r0 199 j ret_from_exception 200 nop 201 202ENTRY(handle_cpe) # CpE #17 203 SAVE_ALL 204 mv r4, r0 205 la r8, do_cpe 206 brl r8 207 mv r4, r0 208 j ret_from_exception 209 nop 210 211ENTRY(handle_dbe) # BusEL-data #18 212 SAVE_ALL 213 mv r4, r0 214 la r8, do_be 215 brl r8 216 mv r4, r0 217 j ret_from_exception 218 nop 219 220ENTRY(handle_reserved) # others 221 SAVE_ALL 222 mv r4, r0 223 la r8, do_reserved 224 brl r8 225 mv r4, r0 226 j ret_from_exception 227 nop 228 229#ifndef CONFIG_PREEMPT 230#define resume_kernel restore_all 231#else 232#define __ret_from_irq ret_from_exception 233#endif 234 235 .align 2 236#ifndef CONFIG_PREEMPT 237ENTRY(ret_from_exception) 238 disable_irq # preempt stop 239 nop 240 j __ret_from_irq 241 nop 242#endif 243 244ENTRY(ret_from_irq) 245 sw r16, [r28, TI_REGS] 246 247ENTRY(__ret_from_irq) 248 lw r8, [r0, PT_PSR] # returning to kernel mode? 249 andri.c r8, r8, KU_USER 250 beq resume_kernel 251 252resume_userspace: 253 disable_irq 254 lw r6, [r28, TI_FLAGS] # current->work 255 li r8, _TIF_WORK_MASK 256 and.c r8, r8, r6 # ignoring syscall_trace 257 bne work_pending 258 nop 259 j restore_all 260 nop 261 262#ifdef CONFIG_PREEMPT 263resume_kernel: 264 disable_irq 265 lw r8, [r28, TI_PRE_COUNT] 266 cmpz.c r8 267 bne restore_all 268need_resched: 269 lw r8, [r28, TI_FLAGS] 270 andri.c r9, r8, _TIF_NEED_RESCHED 271 beq restore_all 272 lw r8, [r28, PT_PSR] # Interrupts off? 273 andri.c r8, r8, 1 274 beq restore_all 275 bl preempt_schedule_irq 276 nop 277 j need_resched 278 nop 279#endif 280 281ENTRY(ret_from_kernel_thread) 282 bl schedule_tail # r4=struct task_struct *prev 283 nop 284 mv r4, r13 285 brl r12 286 j syscall_exit 287 288ENTRY(ret_from_fork) 289 bl schedule_tail # r4=struct task_struct *prev 290 291ENTRY(syscall_exit) 292 nop 293 disable_irq 294 lw r6, [r28, TI_FLAGS] # current->work 295 li r8, _TIF_WORK_MASK 296 and.c r8, r6, r8 297 bne syscall_exit_work 298 299ENTRY(restore_all) # restore full frame 300 RESTORE_ALL_AND_RET 301 302work_pending: 303 andri.c r8, r6, _TIF_NEED_RESCHED # r6 is preloaded with TI_FLAGS 304 beq work_notifysig 305work_resched: 306 bl schedule 307 nop 308 disable_irq 309 lw r6, [r28, TI_FLAGS] 310 li r8, _TIF_WORK_MASK 311 and.c r8, r6, r8 # is there any work to be done 312 # other than syscall tracing? 313 beq restore_all 314 andri.c r8, r6, _TIF_NEED_RESCHED 315 bne work_resched 316 317work_notifysig: 318 mv r4, r0 319 li r5, 0 320 bl do_notify_resume # r6 already loaded 321 nop 322 j resume_userspace 323 nop 324 325ENTRY(syscall_exit_work) 326 li r8, _TIF_SYSCALL_TRACE 327 and.c r8, r8, r6 # r6 is preloaded with TI_FLAGS 328 beq work_pending # trace bit set? 329 nop 330 enable_irq 331 mv r4, r0 332 li r5, 1 333 bl do_syscall_trace 334 nop 335 b resume_userspace 336 nop 337 338.macro save_context reg 339 sw r12, [\reg, THREAD_REG12]; 340 sw r13, [\reg, THREAD_REG13]; 341 sw r14, [\reg, THREAD_REG14]; 342 sw r15, [\reg, THREAD_REG15]; 343 sw r16, [\reg, THREAD_REG16]; 344 sw r17, [\reg, THREAD_REG17]; 345 sw r18, [\reg, THREAD_REG18]; 346 sw r19, [\reg, THREAD_REG19]; 347 sw r20, [\reg, THREAD_REG20]; 348 sw r21, [\reg, THREAD_REG21]; 349 sw r29, [\reg, THREAD_REG29]; 350 sw r2, [\reg, THREAD_REG2]; 351 sw r0, [\reg, THREAD_REG0] 352.endm 353 354.macro restore_context reg 355 lw r12, [\reg, THREAD_REG12]; 356 lw r13, [\reg, THREAD_REG13]; 357 lw r14, [\reg, THREAD_REG14]; 358 lw r15, [\reg, THREAD_REG15]; 359 lw r16, [\reg, THREAD_REG16]; 360 lw r17, [\reg, THREAD_REG17]; 361 lw r18, [\reg, THREAD_REG18]; 362 lw r19, [\reg, THREAD_REG19]; 363 lw r20, [\reg, THREAD_REG20]; 364 lw r21, [\reg, THREAD_REG21]; 365 lw r29, [\reg, THREAD_REG29]; 366 lw r0, [\reg, THREAD_REG0]; 367 lw r2, [\reg, THREAD_REG2]; 368 lw r3, [\reg, THREAD_REG3] 369.endm 370 371/* 372 * task_struct *resume(task_struct *prev, task_struct *next, 373 * struct thread_info *next_ti) 374 */ 375ENTRY(resume) 376 mfcr r9, cr0 377 nop 378 nop 379 sw r9, [r4, THREAD_PSR] 380 save_context r4 381 sw r3, [r4, THREAD_REG3] 382 383 mv r28, r6 384 restore_context r5 385 mv r8, r6 386 addi r8, KERNEL_STACK_SIZE 387 subi r8, 32 388 la r9, kernelsp; 389 sw r8, [r9]; 390 391 mfcr r9, cr0 392 ldis r7, 0x00ff 393 nop 394 and r9, r9, r7 395 lw r6, [r5, THREAD_PSR] 396 not r7, r7 397 and r6, r6, r7 398 or r6, r6, r9 399 mtcr r6, cr0 400 nop; nop; nop; nop; nop 401 br r3 402 403ENTRY(handle_sys) 404 SAVE_ALL 405 sw r8, [r0, 16] # argument 5 from user r8 406 sw r9, [r0, 20] # argument 6 from user r9 407 enable_irq 408 409 sw r4, [r0, PT_ORIG_R4] #for restart syscall 410 sw r7, [r0, PT_ORIG_R7] #for restart syscall 411 sw r27, [r0, PT_IS_SYSCALL] # it from syscall 412 413 lw r9, [r0, PT_EPC] # skip syscall on return 414 addi r9, 4 415 sw r9, [r0, PT_EPC] 416 417 cmpi.c r27, __NR_syscalls # check syscall number 418 bcs illegal_syscall 419 420 slli r8, r27, 2 # get syscall routine 421 la r11, sys_call_table 422 add r11, r11, r8 423 lw r10, [r11] # get syscall entry 424 425 cmpz.c r10 426 beq illegal_syscall 427 428 lw r8, [r28, TI_FLAGS] 429 li r9, _TIF_SYSCALL_TRACE 430 and.c r8, r8, r9 431 bne syscall_trace_entry 432 433 brl r10 # Do The Real system call 434 435 cmpi.c r4, 0 436 blt 1f 437 ldi r8, 0 438 sw r8, [r0, PT_R7] 439 b 2f 4401: 441 cmpi.c r4, -MAX_ERRNO - 1 442 ble 2f 443 ldi r8, 0x1; 444 sw r8, [r0, PT_R7] 445 neg r4, r4 4462: 447 sw r4, [r0, PT_R4] # save result 448 449syscall_return: 450 disable_irq 451 lw r6, [r28, TI_FLAGS] # current->work 452 li r8, _TIF_WORK_MASK 453 and.c r8, r6, r8 454 bne syscall_return_work 455 j restore_all 456 457syscall_return_work: 458 j syscall_exit_work 459 460syscall_trace_entry: 461 mv r16, r10 462 mv r4, r0 463 li r5, 0 464 bl do_syscall_trace 465 466 mv r8, r16 467 lw r4, [r0, PT_R4] # Restore argument registers 468 lw r5, [r0, PT_R5] 469 lw r6, [r0, PT_R6] 470 lw r7, [r0, PT_R7] 471 brl r8 472 473 li r8, -MAX_ERRNO - 1 474 sw r8, [r0, PT_R7] # set error flag 475 476 neg r4, r4 # error 477 sw r4, [r0, PT_R0] # set flag for syscall 478 # restarting 4791: sw r4, [r0, PT_R2] # result 480 j syscall_exit 481 482illegal_syscall: 483 ldi r4, -ENOSYS # error 484 sw r4, [r0, PT_ORIG_R4] 485 sw r4, [r0, PT_R4] 486 ldi r9, 1 # set error flag 487 sw r9, [r0, PT_R7] 488 j syscall_return 489 490ENTRY(sys_rt_sigreturn) 491 mv r4, r0 492 la r8, score_rt_sigreturn 493 br r8 494