diff options
Diffstat (limited to 'arch/microblaze/kernel/entry.S')
-rw-r--r-- | arch/microblaze/kernel/entry.S | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index c7353e79f4a2..acc1f05d1e2c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -308,38 +308,69 @@ C_ENTRY(_user_exception): | |||
308 | swi r12, r1, PTO+PT_R0; | 308 | swi r12, r1, PTO+PT_R0; |
309 | tovirt(r1,r1) | 309 | tovirt(r1,r1) |
310 | 310 | ||
311 | la r15, r0, ret_from_trap-8 | ||
312 | /* where the trap should return need -8 to adjust for rtsd r15, 8*/ | 311 | /* where the trap should return need -8 to adjust for rtsd r15, 8*/ |
313 | /* Jump to the appropriate function for the system call number in r12 | 312 | /* Jump to the appropriate function for the system call number in r12 |
314 | * (r12 is not preserved), or return an error if r12 is not valid. The LP | 313 | * (r12 is not preserved), or return an error if r12 is not valid. The LP |
315 | * register should point to the location where | 314 | * register should point to the location where |
316 | * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ | 315 | * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ |
317 | /* See if the system call number is valid. */ | 316 | |
317 | # Step into virtual mode. | ||
318 | set_vms; | ||
319 | addik r11, r0, 3f | ||
320 | rtid r11, 0 | ||
321 | nop | ||
322 | 3: | ||
323 | add r11, r0, CURRENT_TASK /* Get current task ptr into r11 */ | ||
324 | lwi r11, r11, TS_THREAD_INFO /* get thread info */ | ||
325 | lwi r11, r11, TI_FLAGS /* get flags in thread info */ | ||
326 | andi r11, r11, _TIF_WORK_SYSCALL_MASK | ||
327 | beqi r11, 4f | ||
328 | |||
329 | addik r3, r0, -ENOSYS | ||
330 | swi r3, r1, PTO + PT_R3 | ||
331 | brlid r15, do_syscall_trace_enter | ||
332 | addik r5, r1, PTO + PT_R0 | ||
333 | |||
334 | # do_syscall_trace_enter returns the new syscall nr. | ||
335 | addk r12, r0, r3 | ||
336 | lwi r5, r1, PTO+PT_R5; | ||
337 | lwi r6, r1, PTO+PT_R6; | ||
338 | lwi r7, r1, PTO+PT_R7; | ||
339 | lwi r8, r1, PTO+PT_R8; | ||
340 | lwi r9, r1, PTO+PT_R9; | ||
341 | lwi r10, r1, PTO+PT_R10; | ||
342 | 4: | ||
343 | /* Jump to the appropriate function for the system call number in r12 | ||
344 | * (r12 is not preserved), or return an error if r12 is not valid. | ||
345 | * The LP register should point to the location where the called function | ||
346 | * should return. [note that MAKE_SYS_CALL uses label 1] */ | ||
347 | /* See if the system call number is valid */ | ||
318 | addi r11, r12, -__NR_syscalls; | 348 | addi r11, r12, -__NR_syscalls; |
319 | bgei r11,1f; | 349 | bgei r11,5f; |
320 | /* Figure out which function to use for this system call. */ | 350 | /* Figure out which function to use for this system call. */ |
321 | /* Note Microblaze barrel shift is optional, so don't rely on it */ | 351 | /* Note Microblaze barrel shift is optional, so don't rely on it */ |
322 | add r12, r12, r12; /* convert num -> ptr */ | 352 | add r12, r12, r12; /* convert num -> ptr */ |
323 | add r12, r12, r12; | 353 | add r12, r12, r12; |
324 | 354 | ||
325 | /* Trac syscalls and stored them to r0_ram */ | 355 | /* Trac syscalls and stored them to r0_ram */ |
326 | lwi r3, r12, 0x400 + TOPHYS(r0_ram) | 356 | lwi r3, r12, 0x400 + r0_ram |
327 | addi r3, r3, 1 | 357 | addi r3, r3, 1 |
328 | swi r3, r12, 0x400 + TOPHYS(r0_ram) | 358 | swi r3, r12, 0x400 + r0_ram |
359 | |||
360 | # Find and jump into the syscall handler. | ||
361 | lwi r12, r12, sys_call_table | ||
362 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
363 | la r15, r0, ret_from_trap-8 | ||
364 | bra r12 | ||
329 | 365 | ||
330 | lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */ | ||
331 | /* Make the system call. to r12*/ | ||
332 | set_vms; | ||
333 | rtid r12, 0; | ||
334 | nop; | ||
335 | /* The syscall number is invalid, return an error. */ | 366 | /* The syscall number is invalid, return an error. */ |
336 | 1: VM_ON; /* RETURN() expects virtual mode*/ | 367 | 5: |
337 | addi r3, r0, -ENOSYS; | 368 | addi r3, r0, -ENOSYS; |
338 | rtsd r15,8; /* looks like a normal subroutine return */ | 369 | rtsd r15,8; /* looks like a normal subroutine return */ |
339 | or r0, r0, r0 | 370 | or r0, r0, r0 |
340 | 371 | ||
341 | 372 | ||
342 | /* Entry point used to return from a syscall/trap. */ | 373 | /* Entry point used to return from a syscall/trap */ |
343 | /* We re-enable BIP bit before state restore */ | 374 | /* We re-enable BIP bit before state restore */ |
344 | C_ENTRY(ret_from_trap): | 375 | C_ENTRY(ret_from_trap): |
345 | set_bip; /* Ints masked for state restore*/ | 376 | set_bip; /* Ints masked for state restore*/ |
@@ -349,6 +380,23 @@ C_ENTRY(ret_from_trap): | |||
349 | 380 | ||
350 | /* We're returning to user mode, so check for various conditions that | 381 | /* We're returning to user mode, so check for various conditions that |
351 | * trigger rescheduling. */ | 382 | * trigger rescheduling. */ |
383 | # FIXME: Restructure all these flag checks. | ||
384 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
385 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
386 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
387 | andi r11, r11, _TIF_WORK_SYSCALL_MASK | ||
388 | beqi r11, 1f | ||
389 | |||
390 | swi r3, r1, PTO + PT_R3 | ||
391 | swi r4, r1, PTO + PT_R4 | ||
392 | brlid r15, do_syscall_trace_leave | ||
393 | addik r5, r1, PTO + PT_R0 | ||
394 | lwi r3, r1, PTO + PT_R3 | ||
395 | lwi r4, r1, PTO + PT_R4 | ||
396 | 1: | ||
397 | |||
398 | /* We're returning to user mode, so check for various conditions that | ||
399 | * trigger rescheduling. */ | ||
352 | /* Get current task ptr into r11 */ | 400 | /* Get current task ptr into r11 */ |
353 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | 401 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ |
354 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | 402 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ |