Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m32r/kernel/entry.S
10817 views
1
/*
2
* linux/arch/m32r/kernel/entry.S
3
*
4
* Copyright (c) 2001, 2002 Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
5
* Copyright (c) 2003 Hitoshi Yamamoto
6
* Copyright (c) 2004 Hirokazu Takata <takata at linux-m32r.org>
7
*
8
* Taken from i386 version.
9
* Copyright (C) 1991, 1992 Linus Torvalds
10
*/
11
12
/*
13
* entry.S contains the system-call and fault low-level handling routines.
14
* This also contains the timer-interrupt handler, as well as all interrupts
15
* and faults that can result in a task-switch.
16
*
17
* NOTE: This code handles signal-recognition, which happens every time
18
* after a timer-interrupt and after each system call.
19
*
20
* Stack layout in 'ret_from_system_call':
21
* ptrace needs to have all regs on the stack.
22
* if the order here is changed, it needs to be
23
* updated in fork.c:copy_thread, signal.c:do_signal,
24
* ptrace.c and ptrace.h
25
*
26
* M32R/M32Rx/M32R2
27
* @(sp) - r4
28
* @(0x04,sp) - r5
29
* @(0x08,sp) - r6
30
* @(0x0c,sp) - *pt_regs
31
* @(0x10,sp) - r0
32
* @(0x14,sp) - r1
33
* @(0x18,sp) - r2
34
* @(0x1c,sp) - r3
35
* @(0x20,sp) - r7
36
* @(0x24,sp) - r8
37
* @(0x28,sp) - r9
38
* @(0x2c,sp) - r10
39
* @(0x30,sp) - r11
40
* @(0x34,sp) - r12
41
* @(0x38,sp) - syscall_nr
42
* @(0x3c,sp) - acc0h
43
* @(0x40,sp) - acc0l
44
* @(0x44,sp) - acc1h ; ISA_DSP_LEVEL2 only
45
* @(0x48,sp) - acc1l ; ISA_DSP_LEVEL2 only
46
* @(0x4c,sp) - psw
47
* @(0x50,sp) - bpc
48
* @(0x54,sp) - bbpsw
49
* @(0x58,sp) - bbpc
50
* @(0x5c,sp) - spu (cr3)
51
* @(0x60,sp) - fp (r13)
52
* @(0x64,sp) - lr (r14)
53
* @(0x68,sp) - spi (cr2)
54
* @(0x6c,sp) - orig_r0
55
*/
56
57
#include <linux/linkage.h>
58
#include <asm/irq.h>
59
#include <asm/unistd.h>
60
#include <asm/assembler.h>
61
#include <asm/thread_info.h>
62
#include <asm/errno.h>
63
#include <asm/segment.h>
64
#include <asm/smp.h>
65
#include <asm/page.h>
66
#include <asm/m32r.h>
67
#include <asm/mmu_context.h>
68
69
#if !defined(CONFIG_MMU)
70
#define sys_madvise sys_ni_syscall
71
#define sys_readahead sys_ni_syscall
72
#define sys_mprotect sys_ni_syscall
73
#define sys_msync sys_ni_syscall
74
#define sys_mlock sys_ni_syscall
75
#define sys_munlock sys_ni_syscall
76
#define sys_mlockall sys_ni_syscall
77
#define sys_munlockall sys_ni_syscall
78
#define sys_mremap sys_ni_syscall
79
#define sys_mincore sys_ni_syscall
80
#define sys_remap_file_pages sys_ni_syscall
81
#endif /* CONFIG_MMU */
82
83
#define R4(reg) @reg
84
#define R5(reg) @(0x04,reg)
85
#define R6(reg) @(0x08,reg)
86
#define PTREGS(reg) @(0x0C,reg)
87
#define R0(reg) @(0x10,reg)
88
#define R1(reg) @(0x14,reg)
89
#define R2(reg) @(0x18,reg)
90
#define R3(reg) @(0x1C,reg)
91
#define R7(reg) @(0x20,reg)
92
#define R8(reg) @(0x24,reg)
93
#define R9(reg) @(0x28,reg)
94
#define R10(reg) @(0x2C,reg)
95
#define R11(reg) @(0x30,reg)
96
#define R12(reg) @(0x34,reg)
97
#define SYSCALL_NR(reg) @(0x38,reg)
98
#define ACC0H(reg) @(0x3C,reg)
99
#define ACC0L(reg) @(0x40,reg)
100
#define ACC1H(reg) @(0x44,reg)
101
#define ACC1L(reg) @(0x48,reg)
102
#define PSW(reg) @(0x4C,reg)
103
#define BPC(reg) @(0x50,reg)
104
#define BBPSW(reg) @(0x54,reg)
105
#define BBPC(reg) @(0x58,reg)
106
#define SPU(reg) @(0x5C,reg)
107
#define FP(reg) @(0x60,reg) /* FP = R13 */
108
#define LR(reg) @(0x64,reg)
109
#define SP(reg) @(0x68,reg)
110
#define ORIG_R0(reg) @(0x6C,reg)
111
112
#define nr_syscalls ((syscall_table_size)/4)
113
114
#ifdef CONFIG_PREEMPT
115
#define preempt_stop(x) DISABLE_INTERRUPTS(x)
116
#else
117
#define preempt_stop(x)
118
#define resume_kernel restore_all
119
#endif
120
121
/* how to get the thread information struct from ASM */
122
#define GET_THREAD_INFO(reg) GET_THREAD_INFO reg
123
.macro GET_THREAD_INFO reg
124
ldi \reg, #-THREAD_SIZE
125
and \reg, sp
126
.endm
127
128
ENTRY(ret_from_fork)
129
pop r0
130
bl schedule_tail
131
GET_THREAD_INFO(r8)
132
bra syscall_exit
133
134
/*
135
* Return to user mode is not as complex as all this looks,
136
* but we want the default path for a system call return to
137
* go as quickly as possible which is why some of this is
138
* less clear than it otherwise should be.
139
*/
140
141
; userspace resumption stub bypassing syscall exit tracing
142
ALIGN
143
ret_from_exception:
144
preempt_stop(r4)
145
ret_from_intr:
146
ld r4, PSW(sp)
147
#ifdef CONFIG_ISA_M32R2
148
and3 r4, r4, #0x8800 ; check BSM and BPM bits
149
#else
150
and3 r4, r4, #0x8000 ; check BSM bit
151
#endif
152
beqz r4, resume_kernel
153
resume_userspace:
154
DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
155
; setting need_resched or sigpending
156
; between sampling and the iret
157
GET_THREAD_INFO(r8)
158
ld r9, @(TI_FLAGS, r8)
159
and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
160
; int/exception return?
161
bnez r4, work_pending
162
bra restore_all
163
164
#ifdef CONFIG_PREEMPT
165
ENTRY(resume_kernel)
166
GET_THREAD_INFO(r8)
167
ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
168
bnez r9, restore_all
169
need_resched:
170
ld r9, @(TI_FLAGS, r8) ; need_resched set ?
171
and3 r4, r9, #_TIF_NEED_RESCHED
172
beqz r4, restore_all
173
ld r4, PSW(sp) ; interrupts off (exception path) ?
174
and3 r4, r4, #0x4000
175
beqz r4, restore_all
176
LDIMM (r4, PREEMPT_ACTIVE)
177
st r4, @(TI_PRE_COUNT, r8)
178
ENABLE_INTERRUPTS(r4)
179
bl schedule
180
ldi r4, #0
181
st r4, @(TI_PRE_COUNT, r8)
182
DISABLE_INTERRUPTS(r4)
183
bra need_resched
184
#endif
185
186
; system call handler stub
187
ENTRY(system_call)
188
SWITCH_TO_KERNEL_STACK
189
SAVE_ALL
190
ENABLE_INTERRUPTS(r4) ; Enable interrupt
191
st sp, PTREGS(sp) ; implicit pt_regs parameter
192
cmpui r7, #NR_syscalls
193
bnc syscall_badsys
194
st r7, SYSCALL_NR(sp) ; syscall_nr
195
; system call tracing in operation
196
GET_THREAD_INFO(r8)
197
ld r9, @(TI_FLAGS, r8)
198
and3 r4, r9, #_TIF_SYSCALL_TRACE
199
bnez r4, syscall_trace_entry
200
syscall_call:
201
slli r7, #2 ; table jump for the system call
202
LDIMM (r4, sys_call_table)
203
add r7, r4
204
ld r7, @r7
205
jl r7 ; execute system call
206
st r0, R0(sp) ; save the return value
207
syscall_exit:
208
DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
209
; setting need_resched or sigpending
210
; between sampling and the iret
211
ld r9, @(TI_FLAGS, r8)
212
and3 r4, r9, #_TIF_ALLWORK_MASK ; current->work
213
bnez r4, syscall_exit_work
214
restore_all:
215
RESTORE_ALL
216
217
# perform work that needs to be done immediately before resumption
218
# r9 : flags
219
ALIGN
220
work_pending:
221
and3 r4, r9, #_TIF_NEED_RESCHED
222
beqz r4, work_notifysig
223
work_resched:
224
bl schedule
225
DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
226
; setting need_resched or sigpending
227
; between sampling and the iret
228
ld r9, @(TI_FLAGS, r8)
229
and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
230
; than syscall tracing?
231
beqz r4, restore_all
232
and3 r4, r4, #_TIF_NEED_RESCHED
233
bnez r4, work_resched
234
235
work_notifysig: ; deal with pending signals and
236
; notify-resume requests
237
mv r0, sp ; arg1 : struct pt_regs *regs
238
mv r1, r9 ; arg2 : __u32 thread_info_flags
239
bl do_notify_resume
240
bra resume_userspace
241
242
; perform syscall exit tracing
243
ALIGN
244
syscall_trace_entry:
245
ldi r4, #-ENOSYS
246
st r4, R0(sp)
247
bl do_syscall_trace
248
ld r0, ORIG_R0(sp)
249
ld r1, R1(sp)
250
ld r2, R2(sp)
251
ld r3, R3(sp)
252
ld r4, R4(sp)
253
ld r5, R5(sp)
254
ld r6, R6(sp)
255
ld r7, SYSCALL_NR(sp)
256
cmpui r7, #NR_syscalls
257
bc syscall_call
258
bra syscall_exit
259
260
; perform syscall exit tracing
261
ALIGN
262
syscall_exit_work:
263
ld r9, @(TI_FLAGS, r8)
264
and3 r4, r9, #_TIF_SYSCALL_TRACE
265
beqz r4, work_pending
266
ENABLE_INTERRUPTS(r4) ; could let do_syscall_trace() call
267
; schedule() instead
268
bl do_syscall_trace
269
bra resume_userspace
270
271
ALIGN
272
syscall_fault:
273
SAVE_ALL
274
GET_THREAD_INFO(r8)
275
ldi r4, #-EFAULT
276
st r4, R0(sp)
277
bra resume_userspace
278
279
ALIGN
280
syscall_badsys:
281
ldi r4, #-ENOSYS
282
st r4, R0(sp)
283
bra resume_userspace
284
285
.global eit_vector
286
287
.equ ei_vec_table, eit_vector + 0x0200
288
289
/*
290
* EI handler routine
291
*/
292
ENTRY(ei_handler)
293
#if defined(CONFIG_CHIP_M32700)
294
; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
295
SWITCH_TO_KERNEL_STACK
296
#endif
297
SAVE_ALL
298
mv r1, sp ; arg1(regs)
299
; get ICU status
300
seth r0, #shigh(M32R_ICU_ISTS_ADDR)
301
ld r0, @(low(M32R_ICU_ISTS_ADDR),r0)
302
push r0
303
#if defined(CONFIG_SMP)
304
/*
305
* If IRQ == 0 --> Nothing to do, Not write IMASK
306
* If IRQ == IPI --> Do IPI handler, Not write IMASK
307
* If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK
308
*/
309
slli r0, #4
310
srli r0, #24 ; r0(irq_num<<2)
311
;; IRQ exist check
312
#if defined(CONFIG_CHIP_M32700)
313
/* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
314
bnez r0, 0f
315
ld24 r14, #0x00070000
316
seth r0, #shigh(M32R_ICU_IMASK_ADDR)
317
st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
318
bra 1f
319
.fillinsn
320
0:
321
#endif /* CONFIG_CHIP_M32700 */
322
beqz r0, 1f ; if (!irq_num) goto exit
323
;; IPI check
324
cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
325
bc 2f
326
cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check
327
bnc 2f
328
LDIMM (r2, ei_vec_table)
329
add r2, r0
330
ld r2, @r2
331
beqz r2, 1f ; if (no IPI handler) goto exit
332
mv r0, r1 ; arg0(regs)
333
jl r2
334
.fillinsn
335
1:
336
addi sp, #4
337
bra restore_all
338
.fillinsn
339
2:
340
srli r0, #2
341
#else /* not CONFIG_SMP */
342
srli r0, #22 ; r0(irq)
343
#endif /* not CONFIG_SMP */
344
345
#if defined(CONFIG_PLAT_HAS_INT1ICU)
346
add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt
347
bnez r2, 3f
348
seth r0, #shigh(M32R_INT1ICU_ISTS)
349
lduh r0, @(low(M32R_INT1ICU_ISTS),r0) ; bit10-6 : ISN
350
slli r0, #21
351
srli r0, #27 ; ISN
352
addi r0, #(M32R_INT1ICU_IRQ_BASE)
353
bra check_end
354
.fillinsn
355
3:
356
#endif /* CONFIG_PLAT_HAS_INT1ICU */
357
#if defined(CONFIG_PLAT_HAS_INT0ICU)
358
add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt
359
bnez r2, 4f
360
seth r0, #shigh(M32R_INT0ICU_ISTS)
361
lduh r0, @(low(M32R_INT0ICU_ISTS),r0) ; bit10-6 : ISN
362
slli r0, #21
363
srli r0, #27 ; ISN
364
add3 r0, r0, #(M32R_INT0ICU_IRQ_BASE)
365
bra check_end
366
.fillinsn
367
4:
368
#endif /* CONFIG_PLAT_HAS_INT0ICU */
369
#if defined(CONFIG_PLAT_HAS_INT2ICU)
370
add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt
371
bnez r2, 5f
372
seth r0, #shigh(M32R_INT2ICU_ISTS)
373
lduh r0, @(low(M32R_INT2ICU_ISTS),r0) ; bit10-6 : ISN
374
slli r0, #21
375
srli r0, #27 ; ISN
376
add3 r0, r0, #(M32R_INT2ICU_IRQ_BASE)
377
; bra check_end
378
.fillinsn
379
5:
380
#endif /* CONFIG_PLAT_HAS_INT2ICU */
381
382
check_end:
383
bl do_IRQ
384
pop r14
385
seth r0, #shigh(M32R_ICU_IMASK_ADDR)
386
st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
387
bra ret_from_intr
388
389
/*
390
* Default EIT handler
391
*/
392
ALIGN
393
int_msg:
394
.asciz "Unknown interrupt\n"
395
.byte 0
396
397
ENTRY(default_eit_handler)
398
push r0
399
mvfc r0, psw
400
push r1
401
push r2
402
push r3
403
push r0
404
LDIMM (r0, __KERNEL_DS)
405
mv r0, r1
406
mv r0, r2
407
LDIMM (r0, int_msg)
408
bl printk
409
pop r0
410
pop r3
411
pop r2
412
pop r1
413
mvtc r0, psw
414
pop r0
415
infinit:
416
bra infinit
417
418
#ifdef CONFIG_MMU
419
/*
420
* Access Exception handler
421
*/
422
ENTRY(ace_handler)
423
SWITCH_TO_KERNEL_STACK
424
SAVE_ALL
425
426
seth r2, #shigh(MMU_REG_BASE) /* Check status register */
427
ld r4, @(low(MESTS_offset),r2)
428
st r4, @(low(MESTS_offset),r2)
429
srl3 r1, r4, #4
430
#ifdef CONFIG_CHIP_M32700
431
and3 r1, r1, #0x0000ffff
432
; WORKAROUND: ignore TME bit for the M32700(TS1).
433
#endif /* CONFIG_CHIP_M32700 */
434
beqz r1, inst
435
oprand:
436
ld r2, @(low(MDEVA_offset),r2) ; set address
437
srli r1, #1
438
bra 1f
439
inst:
440
and3 r1, r4, #2
441
srli r1, #1
442
or3 r1, r1, #8
443
mvfc r2, bpc ; set address
444
.fillinsn
445
1:
446
mvfc r3, psw
447
mv r0, sp
448
and3 r3, r3, 0x800
449
srli r3, #9
450
or r1, r3
451
/*
452
* do_page_fault():
453
* r0 : struct pt_regs *regs
454
* r1 : unsigned long error-code
455
* r2 : unsigned long address
456
* error-code:
457
* +------+------+------+------+
458
* | bit3 | bit2 | bit1 | bit0 |
459
* +------+------+------+------+
460
* bit 3 == 0:means data, 1:means instruction
461
* bit 2 == 0:means kernel, 1:means user-mode
462
* bit 1 == 0:means read, 1:means write
463
* bit 0 == 0:means no page found 1:means protection fault
464
*
465
*/
466
bl do_page_fault
467
bra ret_from_intr
468
#endif /* CONFIG_MMU */
469
470
471
ENTRY(alignment_check)
472
/* void alignment_check(int error_code) */
473
SWITCH_TO_KERNEL_STACK
474
SAVE_ALL
475
ldi r1, #0x30 ; error_code
476
mv r0, sp ; pt_regs
477
bl do_alignment_check
478
error_code:
479
bra ret_from_exception
480
481
ENTRY(rie_handler)
482
/* void rie_handler(int error_code) */
483
SWITCH_TO_KERNEL_STACK
484
SAVE_ALL
485
ldi r1, #0x20 ; error_code
486
mv r0, sp ; pt_regs
487
bl do_rie_handler
488
bra error_code
489
490
ENTRY(pie_handler)
491
/* void pie_handler(int error_code) */
492
SWITCH_TO_KERNEL_STACK
493
SAVE_ALL
494
ldi r1, #0 ; error_code ; FIXME
495
mv r0, sp ; pt_regs
496
bl do_pie_handler
497
bra error_code
498
499
ENTRY(debug_trap)
500
/* void debug_trap(void) */
501
.global withdraw_debug_trap
502
SWITCH_TO_KERNEL_STACK
503
SAVE_ALL
504
mv r0, sp ; pt_regs
505
bl withdraw_debug_trap
506
ldi r1, #0 ; error_code
507
mv r0, sp ; pt_regs
508
bl do_debug_trap
509
bra error_code
510
511
ENTRY(ill_trap)
512
/* void ill_trap(void) */
513
SWITCH_TO_KERNEL_STACK
514
SAVE_ALL
515
ldi r1, #0 ; error_code ; FIXME
516
mv r0, sp ; pt_regs
517
bl do_ill_trap
518
bra error_code
519
520
ENTRY(cache_flushing_handler)
521
/* void _flush_cache_all(void); */
522
.global _flush_cache_all
523
SWITCH_TO_KERNEL_STACK
524
push r0
525
push r1
526
push r2
527
push r3
528
push r4
529
push r5
530
push r6
531
push r7
532
push lr
533
bl _flush_cache_all
534
pop lr
535
pop r7
536
pop r6
537
pop r5
538
pop r4
539
pop r3
540
pop r2
541
pop r1
542
pop r0
543
rte
544
545
.section .rodata,"a"
546
#include "syscall_table.S"
547
548
syscall_table_size=(.-sys_call_table)
549
550