Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/microblaze/kernel/entry.S
10817 views
1
/*
2
* Low-level system-call handling, trap handlers and context-switching
3
*
4
* Copyright (C) 2008-2009 Michal Simek <[email protected]>
5
* Copyright (C) 2008-2009 PetaLogix
6
* Copyright (C) 2003 John Williams <[email protected]>
7
* Copyright (C) 2001,2002 NEC Corporation
8
* Copyright (C) 2001,2002 Miles Bader <[email protected]>
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 <[email protected]>
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
41
syscall_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; \
168
2:
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; \
175
1:
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 \
212
lwi r11, r1, PT_MSR; \
213
mts rmsr , r11; \
214
lwi r2, r1, PT_R2; /* restore SDA */ \
215
lwi r3, r1, PT_R3; \
216
lwi r4, r1, PT_R4; \
217
lwi r5, r1, PT_R5; \
218
lwi r6, r1, PT_R6; \
219
lwi r7, r1, PT_R7; \
220
lwi r8, r1, PT_R8; \
221
lwi r9, r1, PT_R9; \
222
lwi r10, r1, PT_R10; \
223
lwi r11, r1, PT_R11; /* restore clobbered regs after rval */\
224
lwi r12, r1, PT_R12; \
225
lwi r13, r1, PT_R13; /* restore SDA2 */ \
226
lwi r14, r1, PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\
227
lwi r15, r1, PT_R15; /* restore LP */ \
228
lwi r16, r1, PT_R16; \
229
lwi r17, r1, PT_R17; \
230
lwi r18, r1, PT_R18; /* restore asm scratch reg */ \
231
lwi r19, r1, PT_R19; \
232
lwi r20, r1, PT_R20; \
233
lwi r21, r1, PT_R21; \
234
lwi r22, r1, PT_R22; \
235
lwi r23, r1, PT_R23; \
236
lwi r24, r1, PT_R24; \
237
lwi r25, r1, PT_R25; \
238
lwi r26, r1, PT_R26; \
239
lwi r27, r1, PT_R27; \
240
lwi r28, r1, PT_R28; \
241
lwi r29, r1, PT_R29; \
242
lwi r30, r1, PT_R30; \
243
lwi r31, r1, PT_R31; /* Restore cur task reg */
244
245
#define SAVE_STATE \
246
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \
247
/* See if already in kernel mode.*/ \
248
mfs r1, rmsr; \
249
andi r1, r1, MSR_UMS; \
250
bnei r1, 1f; \
251
/* Kernel-mode state save. */ \
252
/* Reload kernel stack-ptr. */ \
253
lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
254
/* FIXME: I can add these two lines to one */ \
255
/* tophys(r1,r1); */ \
256
/* addik r1, r1, -PT_SIZE; */ \
257
addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
258
SAVE_REGS \
259
brid 2f; \
260
swi r1, r1, PT_MODE; \
261
1: /* User-mode state save. */ \
262
lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
263
tophys(r1,r1); \
264
lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \
265
/* MS these three instructions can be added to one */ \
266
/* addik r1, r1, THREAD_SIZE; */ \
267
/* tophys(r1,r1); */ \
268
/* addik r1, r1, -PT_SIZE; */ \
269
addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
270
SAVE_REGS \
271
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
272
swi r11, r1, PT_R1; /* Store user SP. */ \
273
swi r0, r1, PT_MODE; /* Was in user-mode. */ \
274
/* MS: I am clearing UMS even in case when I come from kernel space */ \
275
clear_ums; \
276
2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
277
278
.text
279
280
/*
281
* User trap.
282
*
283
* System calls are handled here.
284
*
285
* Syscall protocol:
286
* Syscall number in r12, args in r5-r10
287
* Return value in r3
288
*
289
* Trap entered via brki instruction, so BIP bit is set, and interrupts
290
* are masked. This is nice, means we don't have to CLI before state save
291
*/
292
C_ENTRY(_user_exception):
293
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
294
addi r14, r14, 4 /* return address is 4 byte after call */
295
296
mfs r1, rmsr
297
nop
298
andi r1, r1, MSR_UMS
299
bnei r1, 1f
300
301
/* Kernel-mode state save - kernel execve */
302
lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
303
tophys(r1,r1);
304
305
addik r1, r1, -PT_SIZE; /* Make room on the stack. */
306
SAVE_REGS
307
308
swi r1, r1, PT_MODE; /* pt_regs -> kernel mode */
309
brid 2f;
310
nop; /* Fill delay slot */
311
312
/* User-mode state save. */
313
1:
314
lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
315
tophys(r1,r1);
316
lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
317
/* calculate kernel stack pointer from task struct 8k */
318
addik r1, r1, THREAD_SIZE;
319
tophys(r1,r1);
320
321
addik r1, r1, -PT_SIZE; /* Make room on the stack. */
322
SAVE_REGS
323
swi r0, r1, PT_R3
324
swi r0, r1, PT_R4
325
326
swi r0, r1, PT_MODE; /* Was in user-mode. */
327
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
328
swi r11, r1, PT_R1; /* Store user SP. */
329
clear_ums;
330
2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
331
/* Save away the syscall number. */
332
swi r12, r1, PT_R0;
333
tovirt(r1,r1)
334
335
/* where the trap should return need -8 to adjust for rtsd r15, 8*/
336
/* Jump to the appropriate function for the system call number in r12
337
* (r12 is not preserved), or return an error if r12 is not valid. The LP
338
* register should point to the location where
339
* the called function should return. [note that MAKE_SYS_CALL uses label 1] */
340
341
/* Step into virtual mode */
342
rtbd r0, 3f
343
nop
344
3:
345
lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
346
lwi r11, r11, TI_FLAGS /* get flags in thread info */
347
andi r11, r11, _TIF_WORK_SYSCALL_MASK
348
beqi r11, 4f
349
350
addik r3, r0, -ENOSYS
351
swi r3, r1, PT_R3
352
brlid r15, do_syscall_trace_enter
353
addik r5, r1, PT_R0
354
355
# do_syscall_trace_enter returns the new syscall nr.
356
addk r12, r0, r3
357
lwi r5, r1, PT_R5;
358
lwi r6, r1, PT_R6;
359
lwi r7, r1, PT_R7;
360
lwi r8, r1, PT_R8;
361
lwi r9, r1, PT_R9;
362
lwi r10, r1, PT_R10;
363
4:
364
/* Jump to the appropriate function for the system call number in r12
365
* (r12 is not preserved), or return an error if r12 is not valid.
366
* The LP register should point to the location where the called function
367
* should return. [note that MAKE_SYS_CALL uses label 1] */
368
/* See if the system call number is valid */
369
addi r11, r12, -__NR_syscalls;
370
bgei r11,5f;
371
/* Figure out which function to use for this system call. */
372
/* Note Microblaze barrel shift is optional, so don't rely on it */
373
add r12, r12, r12; /* convert num -> ptr */
374
add r12, r12, r12;
375
376
#ifdef DEBUG
377
/* Trac syscalls and stored them to syscall_debug_table */
378
/* The first syscall location stores total syscall number */
379
lwi r3, r0, syscall_debug_table
380
addi r3, r3, 1
381
swi r3, r0, syscall_debug_table
382
lwi r3, r12, syscall_debug_table
383
addi r3, r3, 1
384
swi r3, r12, syscall_debug_table
385
#endif
386
387
# Find and jump into the syscall handler.
388
lwi r12, r12, sys_call_table
389
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
390
addi r15, r0, ret_from_trap-8
391
bra r12
392
393
/* The syscall number is invalid, return an error. */
394
5:
395
rtsd r15, 8; /* looks like a normal subroutine return */
396
addi r3, r0, -ENOSYS;
397
398
/* Entry point used to return from a syscall/trap */
399
/* We re-enable BIP bit before state restore */
400
C_ENTRY(ret_from_trap):
401
swi r3, r1, PT_R3
402
swi r4, r1, PT_R4
403
404
lwi r11, r1, PT_MODE;
405
/* See if returning to kernel mode, if so, skip resched &c. */
406
bnei r11, 2f;
407
/* We're returning to user mode, so check for various conditions that
408
* trigger rescheduling. */
409
/* FIXME: Restructure all these flag checks. */
410
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
411
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
412
andi r11, r11, _TIF_WORK_SYSCALL_MASK
413
beqi r11, 1f
414
415
brlid r15, do_syscall_trace_leave
416
addik r5, r1, PT_R0
417
1:
418
/* We're returning to user mode, so check for various conditions that
419
* trigger rescheduling. */
420
/* get thread info from current task */
421
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
422
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
423
andi r11, r11, _TIF_NEED_RESCHED;
424
beqi r11, 5f;
425
426
bralid r15, schedule; /* Call scheduler */
427
nop; /* delay slot */
428
429
/* Maybe handle a signal */
430
5: /* get thread info from current task*/
431
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
432
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
433
andi r11, r11, _TIF_SIGPENDING;
434
beqi r11, 1f; /* Signals to handle, handle them */
435
436
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
437
addi r7, r0, 1; /* Arg 3: int in_syscall */
438
bralid r15, do_signal; /* Handle any signals */
439
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
440
441
/* Finally, return to user state. */
442
1: set_bip; /* Ints masked for state restore */
443
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
444
VM_OFF;
445
tophys(r1,r1);
446
RESTORE_REGS;
447
addik r1, r1, PT_SIZE /* Clean up stack space. */
448
lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
449
bri 6f;
450
451
/* Return to kernel state. */
452
2: set_bip; /* Ints masked for state restore */
453
VM_OFF;
454
tophys(r1,r1);
455
RESTORE_REGS;
456
addik r1, r1, PT_SIZE /* Clean up stack space. */
457
tovirt(r1,r1);
458
6:
459
TRAP_return: /* Make global symbol for debugging */
460
rtbd r14, 0; /* Instructions to return from an IRQ */
461
nop;
462
463
464
/* These syscalls need access to the struct pt_regs on the stack, so we
465
implement them in assembly (they're basically all wrappers anyway). */
466
467
C_ENTRY(sys_fork_wrapper):
468
addi r5, r0, SIGCHLD /* Arg 0: flags */
469
lwi r6, r1, PT_R1 /* Arg 1: child SP (use parent's) */
470
addik r7, r1, 0 /* Arg 2: parent context */
471
add r8. r0, r0 /* Arg 3: (unused) */
472
add r9, r0, r0; /* Arg 4: (unused) */
473
brid do_fork /* Do real work (tail-call) */
474
add r10, r0, r0; /* Arg 5: (unused) */
475
476
/* This the initial entry point for a new child thread, with an appropriate
477
stack in place that makes it look the the child is in the middle of an
478
syscall. This function is actually `returned to' from switch_thread
479
(copy_thread makes ret_from_fork the return address in each new thread's
480
saved context). */
481
C_ENTRY(ret_from_fork):
482
bralid r15, schedule_tail; /* ...which is schedule_tail's arg */
483
add r3, r5, r0; /* switch_thread returns the prev task */
484
/* ( in the delay slot ) */
485
brid ret_from_trap; /* Do normal trap return */
486
add r3, r0, r0; /* Child's fork call should return 0. */
487
488
C_ENTRY(sys_vfork):
489
brid microblaze_vfork /* Do real work (tail-call) */
490
addik r5, r1, 0
491
492
C_ENTRY(sys_clone):
493
bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */
494
lwi r6, r1, PT_R1; /* If so, use paret's stack ptr */
495
1: addik r7, r1, 0; /* Arg 2: parent context */
496
add r8, r0, r0; /* Arg 3: (unused) */
497
add r9, r0, r0; /* Arg 4: (unused) */
498
brid do_fork /* Do real work (tail-call) */
499
add r10, r0, r0; /* Arg 5: (unused) */
500
501
C_ENTRY(sys_execve):
502
brid microblaze_execve; /* Do real work (tail-call).*/
503
addik r8, r1, 0; /* add user context as 4th arg */
504
505
C_ENTRY(sys_rt_sigreturn_wrapper):
506
brid sys_rt_sigreturn /* Do real work */
507
addik r5, r1, 0; /* add user context as 1st arg */
508
509
/*
510
* HW EXCEPTION rutine start
511
*/
512
C_ENTRY(full_exception_trap):
513
/* adjust exception address for privileged instruction
514
* for finding where is it */
515
addik r17, r17, -4
516
SAVE_STATE /* Save registers */
517
/* PC, before IRQ/trap - this is one instruction above */
518
swi r17, r1, PT_PC;
519
tovirt(r1,r1)
520
/* FIXME this can be store directly in PT_ESR reg.
521
* I tested it but there is a fault */
522
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
523
addik r15, r0, ret_from_exc - 8
524
mfs r6, resr
525
mfs r7, rfsr; /* save FSR */
526
mts rfsr, r0; /* Clear sticky fsr */
527
rted r0, full_exception
528
addik r5, r1, 0 /* parameter struct pt_regs * regs */
529
530
/*
531
* Unaligned data trap.
532
*
533
* Unaligned data trap last on 4k page is handled here.
534
*
535
* Trap entered via exception, so EE bit is set, and interrupts
536
* are masked. This is nice, means we don't have to CLI before state save
537
*
538
* The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
539
*/
540
C_ENTRY(unaligned_data_trap):
541
/* MS: I have to save r11 value and then restore it because
542
* set_bit, clear_eip, set_ee use r11 as temp register if MSR
543
* instructions are not used. We don't need to do if MSR instructions
544
* are used and they use r0 instead of r11.
545
* I am using ENTRY_SP which should be primary used only for stack
546
* pointer saving. */
547
swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
548
set_bip; /* equalize initial state for all possible entries */
549
clear_eip;
550
set_ee;
551
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
552
SAVE_STATE /* Save registers.*/
553
/* PC, before IRQ/trap - this is one instruction above */
554
swi r17, r1, PT_PC;
555
tovirt(r1,r1)
556
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
557
addik r15, r0, ret_from_exc-8
558
mfs r3, resr /* ESR */
559
mfs r4, rear /* EAR */
560
rtbd r0, _unaligned_data_exception
561
addik r7, r1, 0 /* parameter struct pt_regs * regs */
562
563
/*
564
* Page fault traps.
565
*
566
* If the real exception handler (from hw_exception_handler.S) didn't find
567
* the mapping for the process, then we're thrown here to handle such situation.
568
*
569
* Trap entered via exceptions, so EE bit is set, and interrupts
570
* are masked. This is nice, means we don't have to CLI before state save
571
*
572
* Build a standard exception frame for TLB Access errors. All TLB exceptions
573
* will bail out to this point if they can't resolve the lightweight TLB fault.
574
*
575
* The C function called is in "arch/microblaze/mm/fault.c", declared as:
576
* void do_page_fault(struct pt_regs *regs,
577
* unsigned long address,
578
* unsigned long error_code)
579
*/
580
/* data and intruction trap - which is choose is resolved int fault.c */
581
C_ENTRY(page_fault_data_trap):
582
SAVE_STATE /* Save registers.*/
583
/* PC, before IRQ/trap - this is one instruction above */
584
swi r17, r1, PT_PC;
585
tovirt(r1,r1)
586
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
587
addik r15, r0, ret_from_exc-8
588
mfs r6, rear /* parameter unsigned long address */
589
mfs r7, resr /* parameter unsigned long error_code */
590
rted r0, do_page_fault
591
addik r5, r1, 0 /* parameter struct pt_regs * regs */
592
593
C_ENTRY(page_fault_instr_trap):
594
SAVE_STATE /* Save registers.*/
595
/* PC, before IRQ/trap - this is one instruction above */
596
swi r17, r1, PT_PC;
597
tovirt(r1,r1)
598
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
599
addik r15, r0, ret_from_exc-8
600
mfs r6, rear /* parameter unsigned long address */
601
ori r7, r0, 0 /* parameter unsigned long error_code */
602
rted r0, do_page_fault
603
addik r5, r1, 0 /* parameter struct pt_regs * regs */
604
605
/* Entry point used to return from an exception. */
606
C_ENTRY(ret_from_exc):
607
lwi r11, r1, PT_MODE;
608
bnei r11, 2f; /* See if returning to kernel mode, */
609
/* ... if so, skip resched &c. */
610
611
/* We're returning to user mode, so check for various conditions that
612
trigger rescheduling. */
613
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
614
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
615
andi r11, r11, _TIF_NEED_RESCHED;
616
beqi r11, 5f;
617
618
/* Call the scheduler before returning from a syscall/trap. */
619
bralid r15, schedule; /* Call scheduler */
620
nop; /* delay slot */
621
622
/* Maybe handle a signal */
623
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
624
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
625
andi r11, r11, _TIF_SIGPENDING;
626
beqi r11, 1f; /* Signals to handle, handle them */
627
628
/*
629
* Handle a signal return; Pending signals should be in r18.
630
*
631
* Not all registers are saved by the normal trap/interrupt entry
632
* points (for instance, call-saved registers (because the normal
633
* C-compiler calling sequence in the kernel makes sure they're
634
* preserved), and call-clobbered registers in the case of
635
* traps), but signal handlers may want to examine or change the
636
* complete register state. Here we save anything not saved by
637
* the normal entry sequence, so that it may be safely restored
638
* (in a possibly modified form) after do_signal returns. */
639
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
640
addi r7, r0, 0; /* Arg 3: int in_syscall */
641
bralid r15, do_signal; /* Handle any signals */
642
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
643
644
/* Finally, return to user state. */
645
1: set_bip; /* Ints masked for state restore */
646
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
647
VM_OFF;
648
tophys(r1,r1);
649
650
RESTORE_REGS;
651
addik r1, r1, PT_SIZE /* Clean up stack space. */
652
653
lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
654
bri 6f;
655
/* Return to kernel state. */
656
2: set_bip; /* Ints masked for state restore */
657
VM_OFF;
658
tophys(r1,r1);
659
RESTORE_REGS;
660
addik r1, r1, PT_SIZE /* Clean up stack space. */
661
662
tovirt(r1,r1);
663
6:
664
EXC_return: /* Make global symbol for debugging */
665
rtbd r14, 0; /* Instructions to return from an IRQ */
666
nop;
667
668
/*
669
* HW EXCEPTION rutine end
670
*/
671
672
/*
673
* Hardware maskable interrupts.
674
*
675
* The stack-pointer (r1) should have already been saved to the memory
676
* location PER_CPU(ENTRY_SP).
677
*/
678
C_ENTRY(_interrupt):
679
/* MS: we are in physical address */
680
/* Save registers, switch to proper stack, convert SP to virtual.*/
681
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
682
/* MS: See if already in kernel mode. */
683
mfs r1, rmsr
684
nop
685
andi r1, r1, MSR_UMS
686
bnei r1, 1f
687
688
/* Kernel-mode state save. */
689
lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
690
tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
691
/* save registers */
692
/* MS: Make room on the stack -> activation record */
693
addik r1, r1, -PT_SIZE;
694
SAVE_REGS
695
brid 2f;
696
swi r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */
697
1:
698
/* User-mode state save. */
699
/* MS: get the saved current */
700
lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
701
tophys(r1,r1);
702
lwi r1, r1, TS_THREAD_INFO;
703
addik r1, r1, THREAD_SIZE;
704
tophys(r1,r1);
705
/* save registers */
706
addik r1, r1, -PT_SIZE;
707
SAVE_REGS
708
/* calculate mode */
709
swi r0, r1, PT_MODE;
710
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
711
swi r11, r1, PT_R1;
712
clear_ums;
713
2:
714
lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
715
tovirt(r1,r1)
716
addik r15, r0, irq_call;
717
irq_call:rtbd r0, do_IRQ;
718
addik r5, r1, 0;
719
720
/* MS: we are in virtual mode */
721
ret_from_irq:
722
lwi r11, r1, PT_MODE;
723
bnei r11, 2f;
724
725
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
726
lwi r11, r11, TI_FLAGS; /* MS: get flags from thread info */
727
andi r11, r11, _TIF_NEED_RESCHED;
728
beqi r11, 5f
729
bralid r15, schedule;
730
nop; /* delay slot */
731
732
/* Maybe handle a signal */
733
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
734
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
735
andi r11, r11, _TIF_SIGPENDING;
736
beqid r11, no_intr_resched
737
/* Handle a signal return; Pending signals should be in r18. */
738
addi r7, r0, 0; /* Arg 3: int in_syscall */
739
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
740
bralid r15, do_signal; /* Handle any signals */
741
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
742
743
/* Finally, return to user state. */
744
no_intr_resched:
745
/* Disable interrupts, we are now committed to the state restore */
746
disable_irq
747
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
748
VM_OFF;
749
tophys(r1,r1);
750
RESTORE_REGS
751
addik r1, r1, PT_SIZE /* MS: Clean up stack space. */
752
lwi r1, r1, PT_R1 - PT_SIZE;
753
bri 6f;
754
/* MS: Return to kernel state. */
755
2:
756
#ifdef CONFIG_PREEMPT
757
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
758
/* MS: get preempt_count from thread info */
759
lwi r5, r11, TI_PREEMPT_COUNT;
760
bgti r5, restore;
761
762
lwi r5, r11, TI_FLAGS; /* get flags in thread info */
763
andi r5, r5, _TIF_NEED_RESCHED;
764
beqi r5, restore /* if zero jump over */
765
766
preempt:
767
/* interrupts are off that's why I am calling preempt_chedule_irq */
768
bralid r15, preempt_schedule_irq
769
nop
770
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
771
lwi r5, r11, TI_FLAGS; /* get flags in thread info */
772
andi r5, r5, _TIF_NEED_RESCHED;
773
bnei r5, preempt /* if non zero jump to resched */
774
restore:
775
#endif
776
VM_OFF /* MS: turn off MMU */
777
tophys(r1,r1)
778
RESTORE_REGS
779
addik r1, r1, PT_SIZE /* MS: Clean up stack space. */
780
tovirt(r1,r1);
781
6:
782
IRQ_return: /* MS: Make global symbol for debugging */
783
rtid r14, 0
784
nop
785
786
/*
787
* Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18
788
* and call handling function with saved pt_regs
789
*/
790
C_ENTRY(_debug_exception):
791
/* BIP bit is set on entry, no interrupts can occur */
792
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
793
794
mfs r1, rmsr
795
nop
796
andi r1, r1, MSR_UMS
797
bnei r1, 1f
798
/* MS: Kernel-mode state save - kgdb */
799
lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
800
801
/* BIP bit is set on entry, no interrupts can occur */
802
addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE;
803
SAVE_REGS;
804
/* save all regs to pt_reg structure */
805
swi r0, r1, PT_R0; /* R0 must be saved too */
806
swi r14, r1, PT_R14 /* rewrite saved R14 value */
807
swi r16, r1, PT_PC; /* PC and r16 are the same */
808
/* save special purpose registers to pt_regs */
809
mfs r11, rear;
810
swi r11, r1, PT_EAR;
811
mfs r11, resr;
812
swi r11, r1, PT_ESR;
813
mfs r11, rfsr;
814
swi r11, r1, PT_FSR;
815
816
/* stack pointer is in physical address at it is decrease
817
* by PT_SIZE but we need to get correct R1 value */
818
addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE;
819
swi r11, r1, PT_R1
820
/* MS: r31 - current pointer isn't changed */
821
tovirt(r1,r1)
822
#ifdef CONFIG_KGDB
823
addi r5, r1, 0 /* pass pt_reg address as the first arg */
824
addik r15, r0, dbtrap_call; /* return address */
825
rtbd r0, microblaze_kgdb_break
826
nop;
827
#endif
828
/* MS: Place handler for brki from kernel space if KGDB is OFF.
829
* It is very unlikely that another brki instruction is called. */
830
bri 0
831
832
/* MS: User-mode state save - gdb */
833
1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
834
tophys(r1,r1);
835
lwi r1, r1, TS_THREAD_INFO; /* get the thread info */
836
addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */
837
tophys(r1,r1);
838
839
addik r1, r1, -PT_SIZE; /* Make room on the stack. */
840
SAVE_REGS;
841
swi r16, r1, PT_PC; /* Save LP */
842
swi r0, r1, PT_MODE; /* Was in user-mode. */
843
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
844
swi r11, r1, PT_R1; /* Store user SP. */
845
lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
846
tovirt(r1,r1)
847
set_vms;
848
addik r5, r1, 0;
849
addik r15, r0, dbtrap_call;
850
dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
851
rtbd r0, sw_exception
852
nop
853
854
/* MS: The first instruction for the second part of the gdb/kgdb */
855
set_bip; /* Ints masked for state restore */
856
lwi r11, r1, PT_MODE;
857
bnei r11, 2f;
858
/* MS: Return to user space - gdb */
859
/* Get current task ptr into r11 */
860
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
861
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
862
andi r11, r11, _TIF_NEED_RESCHED;
863
beqi r11, 5f;
864
865
/* Call the scheduler before returning from a syscall/trap. */
866
bralid r15, schedule; /* Call scheduler */
867
nop; /* delay slot */
868
869
/* Maybe handle a signal */
870
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
871
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
872
andi r11, r11, _TIF_SIGPENDING;
873
beqi r11, 1f; /* Signals to handle, handle them */
874
875
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
876
addi r7, r0, 0; /* Arg 3: int in_syscall */
877
bralid r15, do_signal; /* Handle any signals */
878
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
879
880
/* Finally, return to user state. */
881
1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
882
VM_OFF;
883
tophys(r1,r1);
884
/* MS: Restore all regs */
885
RESTORE_REGS
886
addik r1, r1, PT_SIZE /* Clean up stack space */
887
lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
888
DBTRAP_return_user: /* MS: Make global symbol for debugging */
889
rtbd r16, 0; /* MS: Instructions to return from a debug trap */
890
nop;
891
892
/* MS: Return to kernel state - kgdb */
893
2: VM_OFF;
894
tophys(r1,r1);
895
/* MS: Restore all regs */
896
RESTORE_REGS
897
lwi r14, r1, PT_R14;
898
lwi r16, r1, PT_PC;
899
addik r1, r1, PT_SIZE; /* MS: Clean up stack space */
900
tovirt(r1,r1);
901
DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
902
rtbd r16, 0; /* MS: Instructions to return from a debug trap */
903
nop;
904
905
906
ENTRY(_switch_to)
907
/* prepare return value */
908
addk r3, r0, CURRENT_TASK
909
910
/* save registers in cpu_context */
911
/* use r11 and r12, volatile registers, as temp register */
912
/* give start of cpu_context for previous process */
913
addik r11, r5, TI_CPU_CONTEXT
914
swi r1, r11, CC_R1
915
swi r2, r11, CC_R2
916
/* skip volatile registers.
917
* they are saved on stack when we jumped to _switch_to() */
918
/* dedicated registers */
919
swi r13, r11, CC_R13
920
swi r14, r11, CC_R14
921
swi r15, r11, CC_R15
922
swi r16, r11, CC_R16
923
swi r17, r11, CC_R17
924
swi r18, r11, CC_R18
925
/* save non-volatile registers */
926
swi r19, r11, CC_R19
927
swi r20, r11, CC_R20
928
swi r21, r11, CC_R21
929
swi r22, r11, CC_R22
930
swi r23, r11, CC_R23
931
swi r24, r11, CC_R24
932
swi r25, r11, CC_R25
933
swi r26, r11, CC_R26
934
swi r27, r11, CC_R27
935
swi r28, r11, CC_R28
936
swi r29, r11, CC_R29
937
swi r30, r11, CC_R30
938
/* special purpose registers */
939
mfs r12, rmsr
940
swi r12, r11, CC_MSR
941
mfs r12, rear
942
swi r12, r11, CC_EAR
943
mfs r12, resr
944
swi r12, r11, CC_ESR
945
mfs r12, rfsr
946
swi r12, r11, CC_FSR
947
948
/* update r31, the current-give me pointer to task which will be next */
949
lwi CURRENT_TASK, r6, TI_TASK
950
/* stored it to current_save too */
951
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE)
952
953
/* get new process' cpu context and restore */
954
/* give me start where start context of next task */
955
addik r11, r6, TI_CPU_CONTEXT
956
957
/* non-volatile registers */
958
lwi r30, r11, CC_R30
959
lwi r29, r11, CC_R29
960
lwi r28, r11, CC_R28
961
lwi r27, r11, CC_R27
962
lwi r26, r11, CC_R26
963
lwi r25, r11, CC_R25
964
lwi r24, r11, CC_R24
965
lwi r23, r11, CC_R23
966
lwi r22, r11, CC_R22
967
lwi r21, r11, CC_R21
968
lwi r20, r11, CC_R20
969
lwi r19, r11, CC_R19
970
/* dedicated registers */
971
lwi r18, r11, CC_R18
972
lwi r17, r11, CC_R17
973
lwi r16, r11, CC_R16
974
lwi r15, r11, CC_R15
975
lwi r14, r11, CC_R14
976
lwi r13, r11, CC_R13
977
/* skip volatile registers */
978
lwi r2, r11, CC_R2
979
lwi r1, r11, CC_R1
980
981
/* special purpose registers */
982
lwi r12, r11, CC_FSR
983
mts rfsr, r12
984
lwi r12, r11, CC_MSR
985
mts rmsr, r12
986
987
rtsd r15, 8
988
nop
989
990
ENTRY(_reset)
991
brai 0; /* Jump to reset vector */
992
993
/* These are compiled and loaded into high memory, then
994
* copied into place in mach_early_setup */
995
.section .init.ivt, "ax"
996
#if CONFIG_MANUAL_RESET_VECTOR
997
.org 0x0
998
brai CONFIG_MANUAL_RESET_VECTOR
999
#endif
1000
.org 0x8
1001
brai TOPHYS(_user_exception); /* syscall handler */
1002
.org 0x10
1003
brai TOPHYS(_interrupt); /* Interrupt handler */
1004
.org 0x18
1005
brai TOPHYS(_debug_exception); /* debug trap handler */
1006
.org 0x20
1007
brai TOPHYS(_hw_exception_handler); /* HW exception handler */
1008
1009
.section .rodata,"a"
1010
#include "syscall_table.S"
1011
1012
syscall_table_size=(.-sys_call_table)
1013
1014
type_SYSCALL:
1015
.ascii "SYSCALL\0"
1016
type_IRQ:
1017
.ascii "IRQ\0"
1018
type_IRQ_PREEMPT:
1019
.ascii "IRQ (PREEMPTED)\0"
1020
type_SYSCALL_PREEMPT:
1021
.ascii " SYSCALL (PREEMPTED)\0"
1022
1023
/*
1024
* Trap decoding for stack unwinder
1025
* Tuples are (start addr, end addr, string)
1026
* If return address lies on [start addr, end addr],
1027
* unwinder displays 'string'
1028
*/
1029
1030
.align 4
1031
.global microblaze_trap_handlers
1032
microblaze_trap_handlers:
1033
/* Exact matches come first */
1034
.word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL
1035
.word ret_from_irq ; .word ret_from_irq ; .word type_IRQ
1036
/* Fuzzy matches go here */
1037
.word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
1038
.word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT
1039
/* End of table */
1040
.word 0 ; .word 0 ; .word 0
1041
1042