diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-13 13:57:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-13 13:57:48 -0400 |
commit | 67002151403350b497c1efc8d36450974dfca023 (patch) | |
tree | 187e98f0c588c38b54baeee04b491e288e9470be /arch/xtensa | |
parent | 9bf12df31f282e845b3dfaac1e5d5376a041da22 (diff) | |
parent | 8872366df396444d7655287c79ed182d8f47cba6 (diff) |
Merge tag 'xtensa-next-20130912' of git://github.com/czankel/xtensa-linux
Pull Xtensa updates from Chris Zankel.
* tag 'xtensa-next-20130912' of git://github.com/czankel/xtensa-linux:
xtensa: Fix broken allmodconfig build
xtensa: remove CCOUNT_PER_JIFFY
xtensa: fix !CONFIG_XTENSA_CALIBRATE_CCOUNT build failure
xtensa: don't use echo -e needlessly
xtensa: new fast_alloca handler
xtensa: keep a3 and excsave1 on entry to exception handlers
xtensa: enable kernel preemption
xtensa: check thread flags atomically on return from user exception
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/Makefile | 4 | ||||
-rw-r--r-- | arch/xtensa/boot/Makefile | 2 | ||||
-rw-r--r-- | arch/xtensa/include/asm/regs.h | 1 | ||||
-rw-r--r-- | arch/xtensa/include/asm/timex.h | 6 | ||||
-rw-r--r-- | arch/xtensa/kernel/align.S | 5 | ||||
-rw-r--r-- | arch/xtensa/kernel/coprocessor.S | 9 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 387 | ||||
-rw-r--r-- | arch/xtensa/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/xtensa/kernel/time.c | 8 | ||||
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 250 | ||||
-rw-r--r-- | arch/xtensa/kernel/xtensa_ksyms.c | 1 |
11 files changed, 324 insertions, 353 deletions
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 136224b74d4f..81250ece3062 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile | |||
@@ -55,10 +55,10 @@ ifneq ($(CONFIG_LD_NO_RELAX),) | |||
55 | LDFLAGS := --no-relax | 55 | LDFLAGS := --no-relax |
56 | endif | 56 | endif |
57 | 57 | ||
58 | ifeq ($(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1) | 58 | ifeq ($(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1) |
59 | CHECKFLAGS += -D__XTENSA_EB__ | 59 | CHECKFLAGS += -D__XTENSA_EB__ |
60 | endif | 60 | endif |
61 | ifeq ($(shell echo -e __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1) | 61 | ifeq ($(shell echo __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1) |
62 | CHECKFLAGS += -D__XTENSA_EL__ | 62 | CHECKFLAGS += -D__XTENSA_EL__ |
63 | endif | 63 | endif |
64 | 64 | ||
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile index 64ffc4b53df6..ca20a892021b 100644 --- a/arch/xtensa/boot/Makefile +++ b/arch/xtensa/boot/Makefile | |||
@@ -12,7 +12,7 @@ | |||
12 | KBUILD_CFLAGS += -fno-builtin -Iarch/$(ARCH)/boot/include | 12 | KBUILD_CFLAGS += -fno-builtin -Iarch/$(ARCH)/boot/include |
13 | HOSTFLAGS += -Iarch/$(ARCH)/boot/include | 13 | HOSTFLAGS += -Iarch/$(ARCH)/boot/include |
14 | 14 | ||
15 | BIG_ENDIAN := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#") | 15 | BIG_ENDIAN := $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#") |
16 | 16 | ||
17 | export ccflags-y | 17 | export ccflags-y |
18 | export BIG_ENDIAN | 18 | export BIG_ENDIAN |
diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h index b24de6717020..4ba9f516b0e2 100644 --- a/arch/xtensa/include/asm/regs.h +++ b/arch/xtensa/include/asm/regs.h | |||
@@ -82,6 +82,7 @@ | |||
82 | #define PS_CALLINC_SHIFT 16 | 82 | #define PS_CALLINC_SHIFT 16 |
83 | #define PS_CALLINC_MASK 0x00030000 | 83 | #define PS_CALLINC_MASK 0x00030000 |
84 | #define PS_OWB_SHIFT 8 | 84 | #define PS_OWB_SHIFT 8 |
85 | #define PS_OWB_WIDTH 4 | ||
85 | #define PS_OWB_MASK 0x00000F00 | 86 | #define PS_OWB_MASK 0x00000F00 |
86 | #define PS_RING_SHIFT 6 | 87 | #define PS_RING_SHIFT 6 |
87 | #define PS_RING_MASK 0x000000C0 | 88 | #define PS_RING_MASK 0x000000C0 |
diff --git a/arch/xtensa/include/asm/timex.h b/arch/xtensa/include/asm/timex.h index 69f901713fb6..27fa3c170662 100644 --- a/arch/xtensa/include/asm/timex.h +++ b/arch/xtensa/include/asm/timex.h | |||
@@ -35,13 +35,7 @@ | |||
35 | # error "Bad timer number for Linux configurations!" | 35 | # error "Bad timer number for Linux configurations!" |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT | ||
39 | extern unsigned long ccount_freq; | 38 | extern unsigned long ccount_freq; |
40 | #define CCOUNT_PER_JIFFY (ccount_freq / HZ) | ||
41 | #else | ||
42 | #define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ)) | ||
43 | #endif | ||
44 | |||
45 | 39 | ||
46 | typedef unsigned long long cycles_t; | 40 | typedef unsigned long long cycles_t; |
47 | 41 | ||
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S index aa2e87b8566a..d4cef6039a5c 100644 --- a/arch/xtensa/kernel/align.S +++ b/arch/xtensa/kernel/align.S | |||
@@ -146,9 +146,9 @@ | |||
146 | * a0: trashed, original value saved on stack (PT_AREG0) | 146 | * a0: trashed, original value saved on stack (PT_AREG0) |
147 | * a1: a1 | 147 | * a1: a1 |
148 | * a2: new stack pointer, original in DEPC | 148 | * a2: new stack pointer, original in DEPC |
149 | * a3: dispatch table | 149 | * a3: a3 |
150 | * depc: a2, original value saved on stack (PT_DEPC) | 150 | * depc: a2, original value saved on stack (PT_DEPC) |
151 | * excsave_1: a3 | 151 | * excsave_1: dispatch table |
152 | * | 152 | * |
153 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 153 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
154 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 154 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -171,7 +171,6 @@ ENTRY(fast_unaligned) | |||
171 | s32i a8, a2, PT_AREG8 | 171 | s32i a8, a2, PT_AREG8 |
172 | 172 | ||
173 | rsr a0, depc | 173 | rsr a0, depc |
174 | xsr a3, excsave1 | ||
175 | s32i a0, a2, PT_AREG2 | 174 | s32i a0, a2, PT_AREG2 |
176 | s32i a3, a2, PT_AREG3 | 175 | s32i a3, a2, PT_AREG3 |
177 | 176 | ||
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S index 647657484866..a482df5df2b2 100644 --- a/arch/xtensa/kernel/coprocessor.S +++ b/arch/xtensa/kernel/coprocessor.S | |||
@@ -32,9 +32,9 @@ | |||
32 | * a0: trashed, original value saved on stack (PT_AREG0) | 32 | * a0: trashed, original value saved on stack (PT_AREG0) |
33 | * a1: a1 | 33 | * a1: a1 |
34 | * a2: new stack pointer, original in DEPC | 34 | * a2: new stack pointer, original in DEPC |
35 | * a3: dispatch table | 35 | * a3: a3 |
36 | * depc: a2, original value saved on stack (PT_DEPC) | 36 | * depc: a2, original value saved on stack (PT_DEPC) |
37 | * excsave_1: a3 | 37 | * excsave_1: dispatch table |
38 | * | 38 | * |
39 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 39 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
40 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 40 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -225,9 +225,9 @@ ENDPROC(coprocessor_restore) | |||
225 | * a0: trashed, original value saved on stack (PT_AREG0) | 225 | * a0: trashed, original value saved on stack (PT_AREG0) |
226 | * a1: a1 | 226 | * a1: a1 |
227 | * a2: new stack pointer, original in DEPC | 227 | * a2: new stack pointer, original in DEPC |
228 | * a3: dispatch table | 228 | * a3: a3 |
229 | * depc: a2, original value saved on stack (PT_DEPC) | 229 | * depc: a2, original value saved on stack (PT_DEPC) |
230 | * excsave_1: a3 | 230 | * excsave_1: dispatch table |
231 | * | 231 | * |
232 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 232 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
233 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 233 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -245,7 +245,6 @@ ENTRY(fast_coprocessor) | |||
245 | 245 | ||
246 | /* Save remaining registers a1-a3 and SAR */ | 246 | /* Save remaining registers a1-a3 and SAR */ |
247 | 247 | ||
248 | xsr a3, excsave1 | ||
249 | s32i a3, a2, PT_AREG3 | 248 | s32i a3, a2, PT_AREG3 |
250 | rsr a3, sar | 249 | rsr a3, sar |
251 | s32i a1, a2, PT_AREG1 | 250 | s32i a1, a2, PT_AREG1 |
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 9298742f0fd0..de1dfa18d0a1 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
@@ -31,8 +31,6 @@ | |||
31 | /* Unimplemented features. */ | 31 | /* Unimplemented features. */ |
32 | 32 | ||
33 | #undef KERNEL_STACK_OVERFLOW_CHECK | 33 | #undef KERNEL_STACK_OVERFLOW_CHECK |
34 | #undef PREEMPTIBLE_KERNEL | ||
35 | #undef ALLOCA_EXCEPTION_IN_IRAM | ||
36 | 34 | ||
37 | /* Not well tested. | 35 | /* Not well tested. |
38 | * | 36 | * |
@@ -92,9 +90,9 @@ | |||
92 | * a0: trashed, original value saved on stack (PT_AREG0) | 90 | * a0: trashed, original value saved on stack (PT_AREG0) |
93 | * a1: a1 | 91 | * a1: a1 |
94 | * a2: new stack pointer, original value in depc | 92 | * a2: new stack pointer, original value in depc |
95 | * a3: dispatch table | 93 | * a3: a3 |
96 | * depc: a2, original value saved on stack (PT_DEPC) | 94 | * depc: a2, original value saved on stack (PT_DEPC) |
97 | * excsave1: a3 | 95 | * excsave1: dispatch table |
98 | * | 96 | * |
99 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 97 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
100 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 98 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -110,9 +108,8 @@ | |||
110 | 108 | ||
111 | ENTRY(user_exception) | 109 | ENTRY(user_exception) |
112 | 110 | ||
113 | /* Save a2, a3, and depc, restore excsave_1 and set SP. */ | 111 | /* Save a1, a2, a3, and set SP. */ |
114 | 112 | ||
115 | xsr a3, excsave1 | ||
116 | rsr a0, depc | 113 | rsr a0, depc |
117 | s32i a1, a2, PT_AREG1 | 114 | s32i a1, a2, PT_AREG1 |
118 | s32i a0, a2, PT_AREG2 | 115 | s32i a0, a2, PT_AREG2 |
@@ -238,9 +235,9 @@ ENDPROC(user_exception) | |||
238 | * a0: trashed, original value saved on stack (PT_AREG0) | 235 | * a0: trashed, original value saved on stack (PT_AREG0) |
239 | * a1: a1 | 236 | * a1: a1 |
240 | * a2: new stack pointer, original in DEPC | 237 | * a2: new stack pointer, original in DEPC |
241 | * a3: dispatch table | 238 | * a3: a3 |
242 | * depc: a2, original value saved on stack (PT_DEPC) | 239 | * depc: a2, original value saved on stack (PT_DEPC) |
243 | * excsave_1: a3 | 240 | * excsave_1: dispatch table |
244 | * | 241 | * |
245 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 242 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
246 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 243 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -256,9 +253,8 @@ ENDPROC(user_exception) | |||
256 | 253 | ||
257 | ENTRY(kernel_exception) | 254 | ENTRY(kernel_exception) |
258 | 255 | ||
259 | /* Save a0, a2, a3, DEPC and set SP. */ | 256 | /* Save a1, a2, a3, and set SP. */ |
260 | 257 | ||
261 | xsr a3, excsave1 # restore a3, excsave_1 | ||
262 | rsr a0, depc # get a2 | 258 | rsr a0, depc # get a2 |
263 | s32i a1, a2, PT_AREG1 | 259 | s32i a1, a2, PT_AREG1 |
264 | s32i a0, a2, PT_AREG2 | 260 | s32i a0, a2, PT_AREG2 |
@@ -409,7 +405,7 @@ common_exception: | |||
409 | * exception handler and call the exception handler. | 405 | * exception handler and call the exception handler. |
410 | */ | 406 | */ |
411 | 407 | ||
412 | movi a4, exc_table | 408 | rsr a4, excsave1 |
413 | mov a6, a1 # pass stack frame | 409 | mov a6, a1 # pass stack frame |
414 | mov a7, a0 # pass EXCCAUSE | 410 | mov a7, a0 # pass EXCCAUSE |
415 | addx4 a4, a0, a4 | 411 | addx4 a4, a0, a4 |
@@ -423,28 +419,15 @@ common_exception: | |||
423 | .global common_exception_return | 419 | .global common_exception_return |
424 | common_exception_return: | 420 | common_exception_return: |
425 | 421 | ||
426 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
427 | l32i a4, a1, PT_DEPC | ||
428 | /* Double exception means we came here with an exception | ||
429 | * while PS.EXCM was set, i.e. interrupts disabled. | ||
430 | */ | ||
431 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
432 | l32i a4, a1, PT_EXCCAUSE | ||
433 | bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f | ||
434 | /* We came here with an interrupt means interrupts were enabled | ||
435 | * and we'll reenable them on return. | ||
436 | */ | ||
437 | movi a4, trace_hardirqs_on | ||
438 | callx4 a4 | ||
439 | 1: | 422 | 1: |
440 | #endif | 423 | rsil a2, LOCKLEVEL |
441 | 424 | ||
442 | /* Jump if we are returning from kernel exceptions. */ | 425 | /* Jump if we are returning from kernel exceptions. */ |
443 | 426 | ||
444 | 1: l32i a3, a1, PT_PS | 427 | l32i a3, a1, PT_PS |
445 | _bbci.l a3, PS_UM_BIT, 4f | 428 | GET_THREAD_INFO(a2, a1) |
446 | 429 | l32i a4, a2, TI_FLAGS | |
447 | rsil a2, 0 | 430 | _bbci.l a3, PS_UM_BIT, 6f |
448 | 431 | ||
449 | /* Specific to a user exception exit: | 432 | /* Specific to a user exception exit: |
450 | * We need to check some flags for signal handling and rescheduling, | 433 | * We need to check some flags for signal handling and rescheduling, |
@@ -453,9 +436,6 @@ common_exception_return: | |||
453 | * Note that we don't disable interrupts here. | 436 | * Note that we don't disable interrupts here. |
454 | */ | 437 | */ |
455 | 438 | ||
456 | GET_THREAD_INFO(a2,a1) | ||
457 | l32i a4, a2, TI_FLAGS | ||
458 | |||
459 | _bbsi.l a4, TIF_NEED_RESCHED, 3f | 439 | _bbsi.l a4, TIF_NEED_RESCHED, 3f |
460 | _bbsi.l a4, TIF_NOTIFY_RESUME, 2f | 440 | _bbsi.l a4, TIF_NOTIFY_RESUME, 2f |
461 | _bbci.l a4, TIF_SIGPENDING, 5f | 441 | _bbci.l a4, TIF_SIGPENDING, 5f |
@@ -465,6 +445,7 @@ common_exception_return: | |||
465 | 445 | ||
466 | /* Call do_signal() */ | 446 | /* Call do_signal() */ |
467 | 447 | ||
448 | rsil a2, 0 | ||
468 | movi a4, do_notify_resume # int do_notify_resume(struct pt_regs*) | 449 | movi a4, do_notify_resume # int do_notify_resume(struct pt_regs*) |
469 | mov a6, a1 | 450 | mov a6, a1 |
470 | callx4 a4 | 451 | callx4 a4 |
@@ -472,10 +453,24 @@ common_exception_return: | |||
472 | 453 | ||
473 | 3: /* Reschedule */ | 454 | 3: /* Reschedule */ |
474 | 455 | ||
456 | rsil a2, 0 | ||
475 | movi a4, schedule # void schedule (void) | 457 | movi a4, schedule # void schedule (void) |
476 | callx4 a4 | 458 | callx4 a4 |
477 | j 1b | 459 | j 1b |
478 | 460 | ||
461 | #ifdef CONFIG_PREEMPT | ||
462 | 6: | ||
463 | _bbci.l a4, TIF_NEED_RESCHED, 4f | ||
464 | |||
465 | /* Check current_thread_info->preempt_count */ | ||
466 | |||
467 | l32i a4, a2, TI_PRE_COUNT | ||
468 | bnez a4, 4f | ||
469 | movi a4, preempt_schedule_irq | ||
470 | callx4 a4 | ||
471 | j 1b | ||
472 | #endif | ||
473 | |||
479 | 5: | 474 | 5: |
480 | #ifdef CONFIG_DEBUG_TLB_SANITY | 475 | #ifdef CONFIG_DEBUG_TLB_SANITY |
481 | l32i a4, a1, PT_DEPC | 476 | l32i a4, a1, PT_DEPC |
@@ -483,7 +478,24 @@ common_exception_return: | |||
483 | movi a4, check_tlb_sanity | 478 | movi a4, check_tlb_sanity |
484 | callx4 a4 | 479 | callx4 a4 |
485 | #endif | 480 | #endif |
486 | 4: /* Restore optional registers. */ | 481 | 6: |
482 | 4: | ||
483 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
484 | l32i a4, a1, PT_DEPC | ||
485 | /* Double exception means we came here with an exception | ||
486 | * while PS.EXCM was set, i.e. interrupts disabled. | ||
487 | */ | ||
488 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
489 | l32i a4, a1, PT_EXCCAUSE | ||
490 | bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f | ||
491 | /* We came here with an interrupt means interrupts were enabled | ||
492 | * and we'll reenable them on return. | ||
493 | */ | ||
494 | movi a4, trace_hardirqs_on | ||
495 | callx4 a4 | ||
496 | 1: | ||
497 | #endif | ||
498 | /* Restore optional registers. */ | ||
487 | 499 | ||
488 | load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT | 500 | load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT |
489 | 501 | ||
@@ -570,29 +582,6 @@ user_exception_exit: | |||
570 | 582 | ||
571 | kernel_exception_exit: | 583 | kernel_exception_exit: |
572 | 584 | ||
573 | #ifdef PREEMPTIBLE_KERNEL | ||
574 | |||
575 | #ifdef CONFIG_PREEMPT | ||
576 | |||
577 | /* | ||
578 | * Note: We've just returned from a call4, so we have | ||
579 | * at least 4 addt'l regs. | ||
580 | */ | ||
581 | |||
582 | /* Check current_thread_info->preempt_count */ | ||
583 | |||
584 | GET_THREAD_INFO(a2) | ||
585 | l32i a3, a2, TI_PREEMPT | ||
586 | bnez a3, 1f | ||
587 | |||
588 | l32i a2, a2, TI_FLAGS | ||
589 | |||
590 | 1: | ||
591 | |||
592 | #endif | ||
593 | |||
594 | #endif | ||
595 | |||
596 | /* Check if we have to do a movsp. | 585 | /* Check if we have to do a movsp. |
597 | * | 586 | * |
598 | * We only have to do a movsp if the previous window-frame has | 587 | * We only have to do a movsp if the previous window-frame has |
@@ -829,176 +818,63 @@ ENDPROC(unrecoverable_exception) | |||
829 | * | 818 | * |
830 | * The ALLOCA handler is entered when user code executes the MOVSP | 819 | * The ALLOCA handler is entered when user code executes the MOVSP |
831 | * instruction and the caller's frame is not in the register file. | 820 | * instruction and the caller's frame is not in the register file. |
832 | * In this case, the caller frame's a0..a3 are on the stack just | ||
833 | * below sp (a1), and this handler moves them. | ||
834 | * | 821 | * |
835 | * For "MOVSP <ar>,<as>" without destination register a1, this routine | 822 | * This algorithm was taken from the Ross Morley's RTOS Porting Layer: |
836 | * simply moves the value from <as> to <ar> without moving the save area. | 823 | * |
824 | * /home/ross/rtos/porting/XtensaRTOS-PortingLayer-20090507/xtensa_vectors.S | ||
825 | * | ||
826 | * It leverages the existing window spill/fill routines and their support for | ||
827 | * double exceptions. The 'movsp' instruction will only cause an exception if | ||
828 | * the next window needs to be loaded. In fact this ALLOCA exception may be | ||
829 | * replaced at some point by changing the hardware to do a underflow exception | ||
830 | * of the proper size instead. | ||
831 | * | ||
832 | * This algorithm simply backs out the register changes started by the user | ||
833 | * excpetion handler, makes it appear that we have started a window underflow | ||
834 | * by rotating the window back and then setting the old window base (OWB) in | ||
835 | * the 'ps' register with the rolled back window base. The 'movsp' instruction | ||
836 | * will be re-executed and this time since the next window frames is in the | ||
837 | * active AR registers it won't cause an exception. | ||
838 | * | ||
839 | * If the WindowUnderflow code gets a TLB miss the page will get mapped | ||
840 | * the the partial windeowUnderflow will be handeled in the double exception | ||
841 | * handler. | ||
837 | * | 842 | * |
838 | * Entry condition: | 843 | * Entry condition: |
839 | * | 844 | * |
840 | * a0: trashed, original value saved on stack (PT_AREG0) | 845 | * a0: trashed, original value saved on stack (PT_AREG0) |
841 | * a1: a1 | 846 | * a1: a1 |
842 | * a2: new stack pointer, original in DEPC | 847 | * a2: new stack pointer, original in DEPC |
843 | * a3: dispatch table | 848 | * a3: a3 |
844 | * depc: a2, original value saved on stack (PT_DEPC) | 849 | * depc: a2, original value saved on stack (PT_DEPC) |
845 | * excsave_1: a3 | 850 | * excsave_1: dispatch table |
846 | * | 851 | * |
847 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 852 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
848 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 853 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
849 | */ | 854 | */ |
850 | 855 | ||
851 | #if XCHAL_HAVE_BE | ||
852 | #define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 4, 4 | ||
853 | #define _EXTUI_MOVSP_DST(ar) extui ar, ar, 0, 4 | ||
854 | #else | ||
855 | #define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 0, 4 | ||
856 | #define _EXTUI_MOVSP_DST(ar) extui ar, ar, 4, 4 | ||
857 | #endif | ||
858 | |||
859 | ENTRY(fast_alloca) | 856 | ENTRY(fast_alloca) |
857 | rsr a0, windowbase | ||
858 | rotw -1 | ||
859 | rsr a2, ps | ||
860 | extui a3, a2, PS_OWB_SHIFT, PS_OWB_WIDTH | ||
861 | xor a3, a3, a4 | ||
862 | l32i a4, a6, PT_AREG0 | ||
863 | l32i a1, a6, PT_DEPC | ||
864 | rsr a6, depc | ||
865 | wsr a1, depc | ||
866 | slli a3, a3, PS_OWB_SHIFT | ||
867 | xor a2, a2, a3 | ||
868 | wsr a2, ps | ||
869 | rsync | ||
860 | 870 | ||
861 | /* We shouldn't be in a double exception. */ | 871 | _bbci.l a4, 31, 4f |
862 | 872 | rotw -1 | |
863 | l32i a0, a2, PT_DEPC | 873 | _bbci.l a8, 30, 8f |
864 | _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double | 874 | rotw -1 |
865 | 875 | j _WindowUnderflow12 | |
866 | rsr a0, depc # get a2 | 876 | 8: j _WindowUnderflow8 |
867 | s32i a4, a2, PT_AREG4 # save a4 and | 877 | 4: j _WindowUnderflow4 |
868 | s32i a0, a2, PT_AREG2 # a2 to stack | ||
869 | |||
870 | /* Exit critical section. */ | ||
871 | |||
872 | movi a0, 0 | ||
873 | s32i a0, a3, EXC_TABLE_FIXUP | ||
874 | |||
875 | /* Restore a3, excsave_1 */ | ||
876 | |||
877 | xsr a3, excsave1 # make sure excsave_1 is valid for dbl. | ||
878 | rsr a4, epc1 # get exception address | ||
879 | s32i a3, a2, PT_AREG3 # save a3 to stack | ||
880 | |||
881 | #ifdef ALLOCA_EXCEPTION_IN_IRAM | ||
882 | #error iram not supported | ||
883 | #else | ||
884 | /* Note: l8ui not allowed in IRAM/IROM!! */ | ||
885 | l8ui a0, a4, 1 # read as(src) from MOVSP instruction | ||
886 | #endif | ||
887 | movi a3, .Lmovsp_src | ||
888 | _EXTUI_MOVSP_SRC(a0) # extract source register number | ||
889 | addx8 a3, a0, a3 | ||
890 | jx a3 | ||
891 | |||
892 | .Lunhandled_double: | ||
893 | wsr a0, excsave1 | ||
894 | movi a0, unrecoverable_exception | ||
895 | callx0 a0 | ||
896 | |||
897 | .align 8 | ||
898 | .Lmovsp_src: | ||
899 | l32i a3, a2, PT_AREG0; _j 1f; .align 8 | ||
900 | mov a3, a1; _j 1f; .align 8 | ||
901 | l32i a3, a2, PT_AREG2; _j 1f; .align 8 | ||
902 | l32i a3, a2, PT_AREG3; _j 1f; .align 8 | ||
903 | l32i a3, a2, PT_AREG4; _j 1f; .align 8 | ||
904 | mov a3, a5; _j 1f; .align 8 | ||
905 | mov a3, a6; _j 1f; .align 8 | ||
906 | mov a3, a7; _j 1f; .align 8 | ||
907 | mov a3, a8; _j 1f; .align 8 | ||
908 | mov a3, a9; _j 1f; .align 8 | ||
909 | mov a3, a10; _j 1f; .align 8 | ||
910 | mov a3, a11; _j 1f; .align 8 | ||
911 | mov a3, a12; _j 1f; .align 8 | ||
912 | mov a3, a13; _j 1f; .align 8 | ||
913 | mov a3, a14; _j 1f; .align 8 | ||
914 | mov a3, a15; _j 1f; .align 8 | ||
915 | |||
916 | 1: | ||
917 | |||
918 | #ifdef ALLOCA_EXCEPTION_IN_IRAM | ||
919 | #error iram not supported | ||
920 | #else | ||
921 | l8ui a0, a4, 0 # read ar(dst) from MOVSP instruction | ||
922 | #endif | ||
923 | addi a4, a4, 3 # step over movsp | ||
924 | _EXTUI_MOVSP_DST(a0) # extract destination register | ||
925 | wsr a4, epc1 # save new epc_1 | ||
926 | |||
927 | _bnei a0, 1, 1f # no 'movsp a1, ax': jump | ||
928 | |||
929 | /* Move the save area. This implies the use of the L32E | ||
930 | * and S32E instructions, because this move must be done with | ||
931 | * the user's PS.RING privilege levels, not with ring 0 | ||
932 | * (kernel's) privileges currently active with PS.EXCM | ||
933 | * set. Note that we have stil registered a fixup routine with the | ||
934 | * double exception vector in case a double exception occurs. | ||
935 | */ | ||
936 | |||
937 | /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */ | ||
938 | |||
939 | l32e a0, a1, -16 | ||
940 | l32e a4, a1, -12 | ||
941 | s32e a0, a3, -16 | ||
942 | s32e a4, a3, -12 | ||
943 | l32e a0, a1, -8 | ||
944 | l32e a4, a1, -4 | ||
945 | s32e a0, a3, -8 | ||
946 | s32e a4, a3, -4 | ||
947 | |||
948 | /* Restore stack-pointer and all the other saved registers. */ | ||
949 | |||
950 | mov a1, a3 | ||
951 | |||
952 | l32i a4, a2, PT_AREG4 | ||
953 | l32i a3, a2, PT_AREG3 | ||
954 | l32i a0, a2, PT_AREG0 | ||
955 | l32i a2, a2, PT_AREG2 | ||
956 | rfe | ||
957 | |||
958 | /* MOVSP <at>,<as> was invoked with <at> != a1. | ||
959 | * Because the stack pointer is not being modified, | ||
960 | * we should be able to just modify the pointer | ||
961 | * without moving any save area. | ||
962 | * The processor only traps these occurrences if the | ||
963 | * caller window isn't live, so unfortunately we can't | ||
964 | * use this as an alternate trap mechanism. | ||
965 | * So we just do the move. This requires that we | ||
966 | * resolve the destination register, not just the source, | ||
967 | * so there's some extra work. | ||
968 | * (PERHAPS NOT REALLY NEEDED, BUT CLEANER...) | ||
969 | */ | ||
970 | |||
971 | /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */ | ||
972 | |||
973 | 1: movi a4, .Lmovsp_dst | ||
974 | addx8 a4, a0, a4 | ||
975 | jx a4 | ||
976 | |||
977 | .align 8 | ||
978 | .Lmovsp_dst: | ||
979 | s32i a3, a2, PT_AREG0; _j 1f; .align 8 | ||
980 | mov a1, a3; _j 1f; .align 8 | ||
981 | s32i a3, a2, PT_AREG2; _j 1f; .align 8 | ||
982 | s32i a3, a2, PT_AREG3; _j 1f; .align 8 | ||
983 | s32i a3, a2, PT_AREG4; _j 1f; .align 8 | ||
984 | mov a5, a3; _j 1f; .align 8 | ||
985 | mov a6, a3; _j 1f; .align 8 | ||
986 | mov a7, a3; _j 1f; .align 8 | ||
987 | mov a8, a3; _j 1f; .align 8 | ||
988 | mov a9, a3; _j 1f; .align 8 | ||
989 | mov a10, a3; _j 1f; .align 8 | ||
990 | mov a11, a3; _j 1f; .align 8 | ||
991 | mov a12, a3; _j 1f; .align 8 | ||
992 | mov a13, a3; _j 1f; .align 8 | ||
993 | mov a14, a3; _j 1f; .align 8 | ||
994 | mov a15, a3; _j 1f; .align 8 | ||
995 | |||
996 | 1: l32i a4, a2, PT_AREG4 | ||
997 | l32i a3, a2, PT_AREG3 | ||
998 | l32i a0, a2, PT_AREG0 | ||
999 | l32i a2, a2, PT_AREG2 | ||
1000 | rfe | ||
1001 | |||
1002 | ENDPROC(fast_alloca) | 878 | ENDPROC(fast_alloca) |
1003 | 879 | ||
1004 | /* | 880 | /* |
@@ -1015,9 +891,9 @@ ENDPROC(fast_alloca) | |||
1015 | * a0: trashed, original value saved on stack (PT_AREG0) | 891 | * a0: trashed, original value saved on stack (PT_AREG0) |
1016 | * a1: a1 | 892 | * a1: a1 |
1017 | * a2: new stack pointer, original in DEPC | 893 | * a2: new stack pointer, original in DEPC |
1018 | * a3: dispatch table | 894 | * a3: a3 |
1019 | * depc: a2, original value saved on stack (PT_DEPC) | 895 | * depc: a2, original value saved on stack (PT_DEPC) |
1020 | * excsave_1: a3 | 896 | * excsave_1: dispatch table |
1021 | */ | 897 | */ |
1022 | 898 | ||
1023 | ENTRY(fast_syscall_kernel) | 899 | ENTRY(fast_syscall_kernel) |
@@ -1064,7 +940,6 @@ ENTRY(fast_syscall_unrecoverable) | |||
1064 | 940 | ||
1065 | l32i a0, a2, PT_AREG0 # restore a0 | 941 | l32i a0, a2, PT_AREG0 # restore a0 |
1066 | xsr a2, depc # restore a2, depc | 942 | xsr a2, depc # restore a2, depc |
1067 | rsr a3, excsave1 | ||
1068 | 943 | ||
1069 | wsr a0, excsave1 | 944 | wsr a0, excsave1 |
1070 | movi a0, unrecoverable_exception | 945 | movi a0, unrecoverable_exception |
@@ -1086,10 +961,10 @@ ENDPROC(fast_syscall_unrecoverable) | |||
1086 | * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) | 961 | * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) |
1087 | * a1: a1 | 962 | * a1: a1 |
1088 | * a2: new stack pointer, original in a0 and DEPC | 963 | * a2: new stack pointer, original in a0 and DEPC |
1089 | * a3: dispatch table, original in excsave_1 | 964 | * a3: a3 |
1090 | * a4..a15: unchanged | 965 | * a4..a15: unchanged |
1091 | * depc: a2, original value saved on stack (PT_DEPC) | 966 | * depc: a2, original value saved on stack (PT_DEPC) |
1092 | * excsave_1: a3 | 967 | * excsave_1: dispatch table |
1093 | * | 968 | * |
1094 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 969 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
1095 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 970 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -1122,8 +997,6 @@ ENDPROC(fast_syscall_unrecoverable) | |||
1122 | 997 | ||
1123 | ENTRY(fast_syscall_xtensa) | 998 | ENTRY(fast_syscall_xtensa) |
1124 | 999 | ||
1125 | xsr a3, excsave1 # restore a3, excsave1 | ||
1126 | |||
1127 | s32i a7, a2, PT_AREG7 # we need an additional register | 1000 | s32i a7, a2, PT_AREG7 # we need an additional register |
1128 | movi a7, 4 # sizeof(unsigned int) | 1001 | movi a7, 4 # sizeof(unsigned int) |
1129 | access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp | 1002 | access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp |
@@ -1186,9 +1059,9 @@ ENDPROC(fast_syscall_xtensa) | |||
1186 | * a0: trashed, original value saved on stack (PT_AREG0) | 1059 | * a0: trashed, original value saved on stack (PT_AREG0) |
1187 | * a1: a1 | 1060 | * a1: a1 |
1188 | * a2: new stack pointer, original in DEPC | 1061 | * a2: new stack pointer, original in DEPC |
1189 | * a3: dispatch table | 1062 | * a3: a3 |
1190 | * depc: a2, original value saved on stack (PT_DEPC) | 1063 | * depc: a2, original value saved on stack (PT_DEPC) |
1191 | * excsave_1: a3 | 1064 | * excsave_1: dispatch table |
1192 | * | 1065 | * |
1193 | * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. | 1066 | * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. |
1194 | */ | 1067 | */ |
@@ -1197,15 +1070,16 @@ ENTRY(fast_syscall_spill_registers) | |||
1197 | 1070 | ||
1198 | /* Register a FIXUP handler (pass current wb as a parameter) */ | 1071 | /* Register a FIXUP handler (pass current wb as a parameter) */ |
1199 | 1072 | ||
1073 | xsr a3, excsave1 | ||
1200 | movi a0, fast_syscall_spill_registers_fixup | 1074 | movi a0, fast_syscall_spill_registers_fixup |
1201 | s32i a0, a3, EXC_TABLE_FIXUP | 1075 | s32i a0, a3, EXC_TABLE_FIXUP |
1202 | rsr a0, windowbase | 1076 | rsr a0, windowbase |
1203 | s32i a0, a3, EXC_TABLE_PARAM | 1077 | s32i a0, a3, EXC_TABLE_PARAM |
1078 | xsr a3, excsave1 # restore a3 and excsave_1 | ||
1204 | 1079 | ||
1205 | /* Save a3 and SAR on stack. */ | 1080 | /* Save a3, a4 and SAR on stack. */ |
1206 | 1081 | ||
1207 | rsr a0, sar | 1082 | rsr a0, sar |
1208 | xsr a3, excsave1 # restore a3 and excsave_1 | ||
1209 | s32i a3, a2, PT_AREG3 | 1083 | s32i a3, a2, PT_AREG3 |
1210 | s32i a4, a2, PT_AREG4 | 1084 | s32i a4, a2, PT_AREG4 |
1211 | s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 | 1085 | s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 |
@@ -1259,14 +1133,14 @@ fast_syscall_spill_registers_fixup: | |||
1259 | * in WS, so that the exception handlers save them to the task stack. | 1133 | * in WS, so that the exception handlers save them to the task stack. |
1260 | */ | 1134 | */ |
1261 | 1135 | ||
1262 | rsr a3, excsave1 # get spill-mask | 1136 | xsr a3, excsave1 # get spill-mask |
1263 | slli a2, a3, 1 # shift left by one | 1137 | slli a2, a3, 1 # shift left by one |
1264 | 1138 | ||
1265 | slli a3, a2, 32-WSBITS | 1139 | slli a3, a2, 32-WSBITS |
1266 | src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy...... | 1140 | src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy...... |
1267 | wsr a2, windowstart # set corrected windowstart | 1141 | wsr a2, windowstart # set corrected windowstart |
1268 | 1142 | ||
1269 | movi a3, exc_table | 1143 | rsr a3, excsave1 |
1270 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2 | 1144 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2 |
1271 | l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task) | 1145 | l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task) |
1272 | 1146 | ||
@@ -1303,7 +1177,7 @@ fast_syscall_spill_registers_fixup: | |||
1303 | 1177 | ||
1304 | /* Jump to the exception handler. */ | 1178 | /* Jump to the exception handler. */ |
1305 | 1179 | ||
1306 | movi a3, exc_table | 1180 | rsr a3, excsave1 |
1307 | rsr a0, exccause | 1181 | rsr a0, exccause |
1308 | addx4 a0, a0, a3 # find entry in table | 1182 | addx4 a0, a0, a3 # find entry in table |
1309 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler | 1183 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler |
@@ -1320,6 +1194,7 @@ fast_syscall_spill_registers_fixup_return: | |||
1320 | xsr a3, excsave1 | 1194 | xsr a3, excsave1 |
1321 | movi a2, fast_syscall_spill_registers_fixup | 1195 | movi a2, fast_syscall_spill_registers_fixup |
1322 | s32i a2, a3, EXC_TABLE_FIXUP | 1196 | s32i a2, a3, EXC_TABLE_FIXUP |
1197 | s32i a0, a3, EXC_TABLE_DOUBLE_SAVE | ||
1323 | rsr a2, windowbase | 1198 | rsr a2, windowbase |
1324 | s32i a2, a3, EXC_TABLE_PARAM | 1199 | s32i a2, a3, EXC_TABLE_PARAM |
1325 | l32i a2, a3, EXC_TABLE_KSTK | 1200 | l32i a2, a3, EXC_TABLE_KSTK |
@@ -1331,11 +1206,6 @@ fast_syscall_spill_registers_fixup_return: | |||
1331 | wsr a3, windowbase | 1206 | wsr a3, windowbase |
1332 | rsync | 1207 | rsync |
1333 | 1208 | ||
1334 | /* Restore a3 and return. */ | ||
1335 | |||
1336 | movi a3, exc_table | ||
1337 | xsr a3, excsave1 | ||
1338 | |||
1339 | rfde | 1209 | rfde |
1340 | 1210 | ||
1341 | 1211 | ||
@@ -1522,9 +1392,8 @@ ENTRY(_spill_registers) | |||
1522 | 1392 | ||
1523 | movi a0, 0 | 1393 | movi a0, 0 |
1524 | 1394 | ||
1525 | movi a3, exc_table | 1395 | rsr a3, excsave1 |
1526 | l32i a1, a3, EXC_TABLE_KSTK | 1396 | l32i a1, a3, EXC_TABLE_KSTK |
1527 | wsr a3, excsave1 | ||
1528 | 1397 | ||
1529 | movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL | 1398 | movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL |
1530 | wsr a4, ps | 1399 | wsr a4, ps |
@@ -1568,9 +1437,9 @@ ENDPROC(fast_second_level_miss_double_kernel) | |||
1568 | * a0: trashed, original value saved on stack (PT_AREG0) | 1437 | * a0: trashed, original value saved on stack (PT_AREG0) |
1569 | * a1: a1 | 1438 | * a1: a1 |
1570 | * a2: new stack pointer, original in DEPC | 1439 | * a2: new stack pointer, original in DEPC |
1571 | * a3: dispatch table | 1440 | * a3: a3 |
1572 | * depc: a2, original value saved on stack (PT_DEPC) | 1441 | * depc: a2, original value saved on stack (PT_DEPC) |
1573 | * excsave_1: a3 | 1442 | * excsave_1: dispatch table |
1574 | * | 1443 | * |
1575 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 1444 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
1576 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 1445 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -1578,9 +1447,10 @@ ENDPROC(fast_second_level_miss_double_kernel) | |||
1578 | 1447 | ||
1579 | ENTRY(fast_second_level_miss) | 1448 | ENTRY(fast_second_level_miss) |
1580 | 1449 | ||
1581 | /* Save a1. Note: we don't expect a double exception. */ | 1450 | /* Save a1 and a3. Note: we don't expect a double exception. */ |
1582 | 1451 | ||
1583 | s32i a1, a2, PT_AREG1 | 1452 | s32i a1, a2, PT_AREG1 |
1453 | s32i a3, a2, PT_AREG3 | ||
1584 | 1454 | ||
1585 | /* We need to map the page of PTEs for the user task. Find | 1455 | /* We need to map the page of PTEs for the user task. Find |
1586 | * the pointer to that page. Also, it's possible for tsk->mm | 1456 | * the pointer to that page. Also, it's possible for tsk->mm |
@@ -1602,9 +1472,6 @@ ENTRY(fast_second_level_miss) | |||
1602 | l32i a0, a1, TASK_MM # tsk->mm | 1472 | l32i a0, a1, TASK_MM # tsk->mm |
1603 | beqz a0, 9f | 1473 | beqz a0, 9f |
1604 | 1474 | ||
1605 | |||
1606 | /* We deliberately destroy a3 that holds the exception table. */ | ||
1607 | |||
1608 | 8: rsr a3, excvaddr # fault address | 1475 | 8: rsr a3, excvaddr # fault address |
1609 | _PGD_OFFSET(a0, a3, a1) | 1476 | _PGD_OFFSET(a0, a3, a1) |
1610 | l32i a0, a0, 0 # read pmdval | 1477 | l32i a0, a0, 0 # read pmdval |
@@ -1655,7 +1522,7 @@ ENTRY(fast_second_level_miss) | |||
1655 | 1522 | ||
1656 | /* Exit critical section. */ | 1523 | /* Exit critical section. */ |
1657 | 1524 | ||
1658 | 4: movi a3, exc_table # restore a3 | 1525 | 4: rsr a3, excsave1 |
1659 | movi a0, 0 | 1526 | movi a0, 0 |
1660 | s32i a0, a3, EXC_TABLE_FIXUP | 1527 | s32i a0, a3, EXC_TABLE_FIXUP |
1661 | 1528 | ||
@@ -1663,8 +1530,8 @@ ENTRY(fast_second_level_miss) | |||
1663 | 1530 | ||
1664 | l32i a0, a2, PT_AREG0 | 1531 | l32i a0, a2, PT_AREG0 |
1665 | l32i a1, a2, PT_AREG1 | 1532 | l32i a1, a2, PT_AREG1 |
1533 | l32i a3, a2, PT_AREG3 | ||
1666 | l32i a2, a2, PT_DEPC | 1534 | l32i a2, a2, PT_DEPC |
1667 | xsr a3, excsave1 | ||
1668 | 1535 | ||
1669 | bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | 1536 | bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f |
1670 | 1537 | ||
@@ -1751,11 +1618,8 @@ ENTRY(fast_second_level_miss) | |||
1751 | 1618 | ||
1752 | 2: /* Invalid PGD, default exception handling */ | 1619 | 2: /* Invalid PGD, default exception handling */ |
1753 | 1620 | ||
1754 | movi a3, exc_table | ||
1755 | rsr a1, depc | 1621 | rsr a1, depc |
1756 | xsr a3, excsave1 | ||
1757 | s32i a1, a2, PT_AREG2 | 1622 | s32i a1, a2, PT_AREG2 |
1758 | s32i a3, a2, PT_AREG3 | ||
1759 | mov a1, a2 | 1623 | mov a1, a2 |
1760 | 1624 | ||
1761 | rsr a2, ps | 1625 | rsr a2, ps |
@@ -1775,9 +1639,9 @@ ENDPROC(fast_second_level_miss) | |||
1775 | * a0: trashed, original value saved on stack (PT_AREG0) | 1639 | * a0: trashed, original value saved on stack (PT_AREG0) |
1776 | * a1: a1 | 1640 | * a1: a1 |
1777 | * a2: new stack pointer, original in DEPC | 1641 | * a2: new stack pointer, original in DEPC |
1778 | * a3: dispatch table | 1642 | * a3: a3 |
1779 | * depc: a2, original value saved on stack (PT_DEPC) | 1643 | * depc: a2, original value saved on stack (PT_DEPC) |
1780 | * excsave_1: a3 | 1644 | * excsave_1: dispatch table |
1781 | * | 1645 | * |
1782 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC | 1646 | * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC |
1783 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception | 1647 | * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception |
@@ -1785,17 +1649,17 @@ ENDPROC(fast_second_level_miss) | |||
1785 | 1649 | ||
1786 | ENTRY(fast_store_prohibited) | 1650 | ENTRY(fast_store_prohibited) |
1787 | 1651 | ||
1788 | /* Save a1 and a4. */ | 1652 | /* Save a1 and a3. */ |
1789 | 1653 | ||
1790 | s32i a1, a2, PT_AREG1 | 1654 | s32i a1, a2, PT_AREG1 |
1791 | s32i a4, a2, PT_AREG4 | 1655 | s32i a3, a2, PT_AREG3 |
1792 | 1656 | ||
1793 | GET_CURRENT(a1,a2) | 1657 | GET_CURRENT(a1,a2) |
1794 | l32i a0, a1, TASK_MM # tsk->mm | 1658 | l32i a0, a1, TASK_MM # tsk->mm |
1795 | beqz a0, 9f | 1659 | beqz a0, 9f |
1796 | 1660 | ||
1797 | 8: rsr a1, excvaddr # fault address | 1661 | 8: rsr a1, excvaddr # fault address |
1798 | _PGD_OFFSET(a0, a1, a4) | 1662 | _PGD_OFFSET(a0, a1, a3) |
1799 | l32i a0, a0, 0 | 1663 | l32i a0, a0, 0 |
1800 | beqz a0, 2f | 1664 | beqz a0, 2f |
1801 | 1665 | ||
@@ -1804,39 +1668,37 @@ ENTRY(fast_store_prohibited) | |||
1804 | * and is not PAGE_NONE. See pgtable.h for possible PTE layouts. | 1668 | * and is not PAGE_NONE. See pgtable.h for possible PTE layouts. |
1805 | */ | 1669 | */ |
1806 | 1670 | ||
1807 | _PTE_OFFSET(a0, a1, a4) | 1671 | _PTE_OFFSET(a0, a1, a3) |
1808 | l32i a4, a0, 0 # read pteval | 1672 | l32i a3, a0, 0 # read pteval |
1809 | movi a1, _PAGE_CA_INVALID | 1673 | movi a1, _PAGE_CA_INVALID |
1810 | ball a4, a1, 2f | 1674 | ball a3, a1, 2f |
1811 | bbci.l a4, _PAGE_WRITABLE_BIT, 2f | 1675 | bbci.l a3, _PAGE_WRITABLE_BIT, 2f |
1812 | 1676 | ||
1813 | movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE | 1677 | movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE |
1814 | or a4, a4, a1 | 1678 | or a3, a3, a1 |
1815 | rsr a1, excvaddr | 1679 | rsr a1, excvaddr |
1816 | s32i a4, a0, 0 | 1680 | s32i a3, a0, 0 |
1817 | 1681 | ||
1818 | /* We need to flush the cache if we have page coloring. */ | 1682 | /* We need to flush the cache if we have page coloring. */ |
1819 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK | 1683 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK |
1820 | dhwb a0, 0 | 1684 | dhwb a0, 0 |
1821 | #endif | 1685 | #endif |
1822 | pdtlb a0, a1 | 1686 | pdtlb a0, a1 |
1823 | wdtlb a4, a0 | 1687 | wdtlb a3, a0 |
1824 | 1688 | ||
1825 | /* Exit critical section. */ | 1689 | /* Exit critical section. */ |
1826 | 1690 | ||
1827 | movi a0, 0 | 1691 | movi a0, 0 |
1692 | rsr a3, excsave1 | ||
1828 | s32i a0, a3, EXC_TABLE_FIXUP | 1693 | s32i a0, a3, EXC_TABLE_FIXUP |
1829 | 1694 | ||
1830 | /* Restore the working registers, and return. */ | 1695 | /* Restore the working registers, and return. */ |
1831 | 1696 | ||
1832 | l32i a4, a2, PT_AREG4 | 1697 | l32i a3, a2, PT_AREG3 |
1833 | l32i a1, a2, PT_AREG1 | 1698 | l32i a1, a2, PT_AREG1 |
1834 | l32i a0, a2, PT_AREG0 | 1699 | l32i a0, a2, PT_AREG0 |
1835 | l32i a2, a2, PT_DEPC | 1700 | l32i a2, a2, PT_DEPC |
1836 | 1701 | ||
1837 | /* Restore excsave1 and a3. */ | ||
1838 | |||
1839 | xsr a3, excsave1 | ||
1840 | bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | 1702 | bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f |
1841 | 1703 | ||
1842 | rsr a2, depc | 1704 | rsr a2, depc |
@@ -1853,11 +1715,8 @@ ENTRY(fast_store_prohibited) | |||
1853 | 1715 | ||
1854 | 2: /* If there was a problem, handle fault in C */ | 1716 | 2: /* If there was a problem, handle fault in C */ |
1855 | 1717 | ||
1856 | rsr a4, depc # still holds a2 | 1718 | rsr a3, depc # still holds a2 |
1857 | xsr a3, excsave1 | 1719 | s32i a3, a2, PT_AREG2 |
1858 | s32i a4, a2, PT_AREG2 | ||
1859 | s32i a3, a2, PT_AREG3 | ||
1860 | l32i a4, a2, PT_AREG4 | ||
1861 | mov a1, a2 | 1720 | mov a1, a2 |
1862 | 1721 | ||
1863 | rsr a2, ps | 1722 | rsr a2, ps |
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 101012bc1ff6..946fb8d06c8b 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c | |||
@@ -584,8 +584,8 @@ c_show(struct seq_file *f, void *slot) | |||
584 | "bogomips\t: %lu.%02lu\n", | 584 | "bogomips\t: %lu.%02lu\n", |
585 | XCHAL_BUILD_UNIQUE_ID, | 585 | XCHAL_BUILD_UNIQUE_ID, |
586 | XCHAL_HAVE_BE ? "big" : "little", | 586 | XCHAL_HAVE_BE ? "big" : "little", |
587 | CCOUNT_PER_JIFFY/(1000000/HZ), | 587 | ccount_freq/1000000, |
588 | (CCOUNT_PER_JIFFY/(10000/HZ)) % 100, | 588 | (ccount_freq/10000) % 100, |
589 | loops_per_jiffy/(500000/HZ), | 589 | loops_per_jiffy/(500000/HZ), |
590 | (loops_per_jiffy/(5000/HZ)) % 100); | 590 | (loops_per_jiffy/(5000/HZ)) % 100); |
591 | 591 | ||
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 24bb0c1776ba..9af3dd88ad7e 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c | |||
@@ -29,9 +29,7 @@ | |||
29 | #include <asm/timex.h> | 29 | #include <asm/timex.h> |
30 | #include <asm/platform.h> | 30 | #include <asm/platform.h> |
31 | 31 | ||
32 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT | ||
33 | unsigned long ccount_freq; /* ccount Hz */ | 32 | unsigned long ccount_freq; /* ccount Hz */ |
34 | #endif | ||
35 | 33 | ||
36 | static cycle_t ccount_read(struct clocksource *cs) | 34 | static cycle_t ccount_read(struct clocksource *cs) |
37 | { | 35 | { |
@@ -129,8 +127,10 @@ void __init time_init(void) | |||
129 | platform_calibrate_ccount(); | 127 | platform_calibrate_ccount(); |
130 | printk("%d.%02d MHz\n", (int)ccount_freq/1000000, | 128 | printk("%d.%02d MHz\n", (int)ccount_freq/1000000, |
131 | (int)(ccount_freq/10000)%100); | 129 | (int)(ccount_freq/10000)%100); |
130 | #else | ||
131 | ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL; | ||
132 | #endif | 132 | #endif |
133 | clocksource_register_hz(&ccount_clocksource, CCOUNT_PER_JIFFY * HZ); | 133 | clocksource_register_hz(&ccount_clocksource, ccount_freq); |
134 | 134 | ||
135 | ccount_timer.evt.cpumask = cpumask_of(0); | 135 | ccount_timer.evt.cpumask = cpumask_of(0); |
136 | ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT); | 136 | ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT); |
@@ -164,7 +164,7 @@ irqreturn_t timer_interrupt (int irq, void *dev_id) | |||
164 | #ifndef CONFIG_GENERIC_CALIBRATE_DELAY | 164 | #ifndef CONFIG_GENERIC_CALIBRATE_DELAY |
165 | void calibrate_delay(void) | 165 | void calibrate_delay(void) |
166 | { | 166 | { |
167 | loops_per_jiffy = CCOUNT_PER_JIFFY; | 167 | loops_per_jiffy = ccount_freq / HZ; |
168 | printk("Calibrating delay loop (skipped)... " | 168 | printk("Calibrating delay loop (skipped)... " |
169 | "%lu.%02lu BogoMIPS preset\n", | 169 | "%lu.%02lu BogoMIPS preset\n", |
170 | loops_per_jiffy/(1000000/HZ), | 170 | loops_per_jiffy/(1000000/HZ), |
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index f9e175382aa9..cb8fd44caabc 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S | |||
@@ -78,6 +78,7 @@ ENTRY(_UserExceptionVector) | |||
78 | s32i a0, a2, PT_DEPC # mark it as a regular exception | 78 | s32i a0, a2, PT_DEPC # mark it as a regular exception |
79 | addx4 a0, a0, a3 # find entry in table | 79 | addx4 a0, a0, a3 # find entry in table |
80 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler | 80 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler |
81 | xsr a3, excsave1 # restore a3 and dispatch table | ||
81 | jx a0 | 82 | jx a0 |
82 | 83 | ||
83 | ENDPROC(_UserExceptionVector) | 84 | ENDPROC(_UserExceptionVector) |
@@ -104,6 +105,7 @@ ENTRY(_KernelExceptionVector) | |||
104 | s32i a0, a2, PT_DEPC # mark it as a regular exception | 105 | s32i a0, a2, PT_DEPC # mark it as a regular exception |
105 | addx4 a0, a0, a3 # find entry in table | 106 | addx4 a0, a0, a3 # find entry in table |
106 | l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address | 107 | l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address |
108 | xsr a3, excsave1 # restore a3 and dispatch table | ||
107 | jx a0 | 109 | jx a0 |
108 | 110 | ||
109 | ENDPROC(_KernelExceptionVector) | 111 | ENDPROC(_KernelExceptionVector) |
@@ -168,7 +170,7 @@ ENDPROC(_KernelExceptionVector) | |||
168 | * | 170 | * |
169 | * a0: DEPC | 171 | * a0: DEPC |
170 | * a1: a1 | 172 | * a1: a1 |
171 | * a2: trashed, original value in EXC_TABLE_DOUBLE_A2 | 173 | * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE |
172 | * a3: exctable | 174 | * a3: exctable |
173 | * depc: a0 | 175 | * depc: a0 |
174 | * excsave_1: a3 | 176 | * excsave_1: a3 |
@@ -204,47 +206,46 @@ ENDPROC(_KernelExceptionVector) | |||
204 | 206 | ||
205 | .section .DoubleExceptionVector.text, "ax" | 207 | .section .DoubleExceptionVector.text, "ax" |
206 | .begin literal_prefix .DoubleExceptionVector | 208 | .begin literal_prefix .DoubleExceptionVector |
209 | .globl _DoubleExceptionVector_WindowUnderflow | ||
210 | .globl _DoubleExceptionVector_WindowOverflow | ||
207 | 211 | ||
208 | ENTRY(_DoubleExceptionVector) | 212 | ENTRY(_DoubleExceptionVector) |
209 | 213 | ||
210 | /* Deliberately destroy excsave (don't assume it's value was valid). */ | 214 | xsr a3, excsave1 |
211 | 215 | s32i a2, a3, EXC_TABLE_DOUBLE_SAVE | |
212 | wsr a3, excsave1 # save a3 | ||
213 | 216 | ||
214 | /* Check for kernel double exception (usually fatal). */ | 217 | /* Check for kernel double exception (usually fatal). */ |
215 | 218 | ||
216 | rsr a3, ps | 219 | rsr a2, ps |
217 | _bbci.l a3, PS_UM_BIT, .Lksp | 220 | _bbci.l a2, PS_UM_BIT, .Lksp |
218 | 221 | ||
219 | /* Check if we are currently handling a window exception. */ | 222 | /* Check if we are currently handling a window exception. */ |
220 | /* Note: We don't need to indicate that we enter a critical section. */ | 223 | /* Note: We don't need to indicate that we enter a critical section. */ |
221 | 224 | ||
222 | xsr a0, depc # get DEPC, save a0 | 225 | xsr a0, depc # get DEPC, save a0 |
223 | 226 | ||
224 | movi a3, WINDOW_VECTORS_VADDR | 227 | movi a2, WINDOW_VECTORS_VADDR |
225 | _bltu a0, a3, .Lfixup | 228 | _bltu a0, a2, .Lfixup |
226 | addi a3, a3, WINDOW_VECTORS_SIZE | 229 | addi a2, a2, WINDOW_VECTORS_SIZE |
227 | _bgeu a0, a3, .Lfixup | 230 | _bgeu a0, a2, .Lfixup |
228 | 231 | ||
229 | /* Window overflow/underflow exception. Get stack pointer. */ | 232 | /* Window overflow/underflow exception. Get stack pointer. */ |
230 | 233 | ||
231 | mov a3, a2 | 234 | l32i a2, a3, EXC_TABLE_KSTK |
232 | /* This explicit literal and the following references to it are made | ||
233 | * in order to fit DoubleExceptionVector.literals into the available | ||
234 | * 16-byte gap before DoubleExceptionVector.text in the absence of | ||
235 | * link time relaxation. See kernel/vmlinux.lds.S | ||
236 | */ | ||
237 | .literal .Lexc_table, exc_table | ||
238 | l32r a2, .Lexc_table | ||
239 | l32i a2, a2, EXC_TABLE_KSTK | ||
240 | 235 | ||
241 | /* Check for overflow/underflow exception, jump if overflow. */ | 236 | /* Check for overflow/underflow exception, jump if overflow. */ |
242 | 237 | ||
243 | _bbci.l a0, 6, .Lovfl | 238 | _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow |
244 | |||
245 | /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ | ||
246 | 239 | ||
247 | /* Restart window underflow exception. | 240 | /* |
241 | * Restart window underflow exception. | ||
242 | * Currently: | ||
243 | * depc = orig a0, | ||
244 | * a0 = orig DEPC, | ||
245 | * a2 = new sp based on KSTK from exc_table | ||
246 | * a3 = excsave_1 | ||
247 | * excsave_1 = orig a3 | ||
248 | * | ||
248 | * We return to the instruction in user space that caused the window | 249 | * We return to the instruction in user space that caused the window |
249 | * underflow exception. Therefore, we change window base to the value | 250 | * underflow exception. Therefore, we change window base to the value |
250 | * before we entered the window underflow exception and prepare the | 251 | * before we entered the window underflow exception and prepare the |
@@ -252,10 +253,11 @@ ENTRY(_DoubleExceptionVector) | |||
252 | * by changing depc (in a0). | 253 | * by changing depc (in a0). |
253 | * Note: We can trash the current window frame (a0...a3) and depc! | 254 | * Note: We can trash the current window frame (a0...a3) and depc! |
254 | */ | 255 | */ |
255 | 256 | _DoubleExceptionVector_WindowUnderflow: | |
257 | xsr a3, excsave1 | ||
256 | wsr a2, depc # save stack pointer temporarily | 258 | wsr a2, depc # save stack pointer temporarily |
257 | rsr a0, ps | 259 | rsr a0, ps |
258 | extui a0, a0, PS_OWB_SHIFT, 4 | 260 | extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH |
259 | wsr a0, windowbase | 261 | wsr a0, windowbase |
260 | rsync | 262 | rsync |
261 | 263 | ||
@@ -263,28 +265,57 @@ ENTRY(_DoubleExceptionVector) | |||
263 | 265 | ||
264 | xsr a2, depc # save a2 and get stack pointer | 266 | xsr a2, depc # save a2 and get stack pointer |
265 | s32i a0, a2, PT_AREG0 | 267 | s32i a0, a2, PT_AREG0 |
266 | 268 | xsr a3, excsave1 | |
267 | wsr a3, excsave1 # save a3 | ||
268 | l32r a3, .Lexc_table | ||
269 | |||
270 | rsr a0, exccause | 269 | rsr a0, exccause |
271 | s32i a0, a2, PT_DEPC # mark it as a regular exception | 270 | s32i a0, a2, PT_DEPC # mark it as a regular exception |
272 | addx4 a0, a0, a3 | 271 | addx4 a0, a0, a3 |
272 | xsr a3, excsave1 | ||
273 | l32i a0, a0, EXC_TABLE_FAST_USER | 273 | l32i a0, a0, EXC_TABLE_FAST_USER |
274 | jx a0 | 274 | jx a0 |
275 | 275 | ||
276 | .Lfixup:/* Check for a fixup handler or if we were in a critical section. */ | 276 | /* |
277 | * We only allow the ITLB miss exception if we are in kernel space. | ||
278 | * All other exceptions are unexpected and thus unrecoverable! | ||
279 | */ | ||
280 | |||
281 | #ifdef CONFIG_MMU | ||
282 | .extern fast_second_level_miss_double_kernel | ||
283 | |||
284 | .Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ | ||
285 | |||
286 | rsr a3, exccause | ||
287 | beqi a3, EXCCAUSE_ITLB_MISS, 1f | ||
288 | addi a3, a3, -EXCCAUSE_DTLB_MISS | ||
289 | bnez a3, .Lunrecoverable | ||
290 | 1: movi a3, fast_second_level_miss_double_kernel | ||
291 | jx a3 | ||
292 | #else | ||
293 | .equ .Lksp, .Lunrecoverable | ||
294 | #endif | ||
295 | |||
296 | /* Critical! We can't handle this situation. PANIC! */ | ||
277 | 297 | ||
278 | /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */ | 298 | .extern unrecoverable_exception |
279 | 299 | ||
280 | l32r a3, .Lexc_table | 300 | .Lunrecoverable_fixup: |
281 | s32i a2, a3, EXC_TABLE_DOUBLE_SAVE # temporary variable | 301 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE |
302 | xsr a0, depc | ||
303 | |||
304 | .Lunrecoverable: | ||
305 | rsr a3, excsave1 | ||
306 | wsr a0, excsave1 | ||
307 | movi a0, unrecoverable_exception | ||
308 | callx0 a0 | ||
309 | |||
310 | .Lfixup:/* Check for a fixup handler or if we were in a critical section. */ | ||
311 | |||
312 | /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */ | ||
282 | 313 | ||
283 | /* Enter critical section. */ | 314 | /* Enter critical section. */ |
284 | 315 | ||
285 | l32i a2, a3, EXC_TABLE_FIXUP | 316 | l32i a2, a3, EXC_TABLE_FIXUP |
286 | s32i a3, a3, EXC_TABLE_FIXUP | 317 | s32i a3, a3, EXC_TABLE_FIXUP |
287 | beq a2, a3, .Lunrecoverable_fixup # critical! | 318 | beq a2, a3, .Lunrecoverable_fixup # critical section |
288 | beqz a2, .Ldflt # no handler was registered | 319 | beqz a2, .Ldflt # no handler was registered |
289 | 320 | ||
290 | /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ | 321 | /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ |
@@ -293,58 +324,145 @@ ENTRY(_DoubleExceptionVector) | |||
293 | 324 | ||
294 | .Ldflt: /* Get stack pointer. */ | 325 | .Ldflt: /* Get stack pointer. */ |
295 | 326 | ||
296 | l32i a3, a3, EXC_TABLE_DOUBLE_SAVE | 327 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE |
297 | addi a2, a3, -PT_USER_SIZE | 328 | addi a2, a2, -PT_USER_SIZE |
298 | |||
299 | .Lovfl: /* Jump to default handlers. */ | ||
300 | 329 | ||
301 | /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ | 330 | /* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */ |
302 | 331 | ||
303 | xsr a3, depc | ||
304 | s32i a0, a2, PT_DEPC | 332 | s32i a0, a2, PT_DEPC |
305 | s32i a3, a2, PT_AREG0 | 333 | l32i a0, a3, EXC_TABLE_DOUBLE_SAVE |
334 | xsr a0, depc | ||
335 | s32i a0, a2, PT_AREG0 | ||
306 | 336 | ||
307 | /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */ | 337 | /* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */ |
308 | 338 | ||
309 | l32r a3, .Lexc_table | ||
310 | rsr a0, exccause | 339 | rsr a0, exccause |
311 | addx4 a0, a0, a3 | 340 | addx4 a0, a0, a3 |
341 | xsr a3, excsave1 | ||
312 | l32i a0, a0, EXC_TABLE_FAST_USER | 342 | l32i a0, a0, EXC_TABLE_FAST_USER |
313 | jx a0 | 343 | jx a0 |
314 | 344 | ||
315 | /* | 345 | /* |
316 | * We only allow the ITLB miss exception if we are in kernel space. | 346 | * Restart window OVERFLOW exception. |
317 | * All other exceptions are unexpected and thus unrecoverable! | 347 | * Currently: |
348 | * depc = orig a0, | ||
349 | * a0 = orig DEPC, | ||
350 | * a2 = new sp based on KSTK from exc_table | ||
351 | * a3 = EXCSAVE_1 | ||
352 | * excsave_1 = orig a3 | ||
353 | * | ||
354 | * We return to the instruction in user space that caused the window | ||
355 | * overflow exception. Therefore, we change window base to the value | ||
356 | * before we entered the window overflow exception and prepare the | ||
357 | * registers to return as if we were coming from a regular exception | ||
358 | * by changing DEPC (in a0). | ||
359 | * | ||
360 | * NOTE: We CANNOT trash the current window frame (a0...a3), but we | ||
361 | * can clobber depc. | ||
362 | * | ||
363 | * The tricky part here is that overflow8 and overflow12 handlers | ||
364 | * save a0, then clobber a0. To restart the handler, we have to restore | ||
365 | * a0 if the double exception was past the point where a0 was clobbered. | ||
366 | * | ||
367 | * To keep things simple, we take advantage of the fact all overflow | ||
368 | * handlers save a0 in their very first instruction. If DEPC was past | ||
369 | * that instruction, we can safely restore a0 from where it was saved | ||
370 | * on the stack. | ||
371 | * | ||
372 | * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3 | ||
318 | */ | 373 | */ |
374 | _DoubleExceptionVector_WindowOverflow: | ||
375 | extui a2, a0, 0, 6 # get offset into 64-byte vector handler | ||
376 | beqz a2, 1f # if at start of vector, don't restore | ||
319 | 377 | ||
320 | #ifdef CONFIG_MMU | 378 | addi a0, a0, -128 |
321 | .extern fast_second_level_miss_double_kernel | 379 | bbsi a0, 8, 1f # don't restore except for overflow 8 and 12 |
380 | bbsi a0, 7, 2f | ||
322 | 381 | ||
323 | .Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ | 382 | /* |
383 | * Restore a0 as saved by _WindowOverflow8(). | ||
384 | * | ||
385 | * FIXME: we really need a fixup handler for this L32E, | ||
386 | * for the extremely unlikely case where the overflow handler's | ||
387 | * reference thru a0 gets a hardware TLB refill that bumps out | ||
388 | * the (distinct, aliasing) TLB entry that mapped its prior | ||
389 | * references thru a9, and where our reference now thru a9 | ||
390 | * gets a 2nd-level miss exception (not hardware TLB refill). | ||
391 | */ | ||
324 | 392 | ||
325 | rsr a3, exccause | 393 | l32e a2, a9, -16 |
326 | beqi a3, EXCCAUSE_ITLB_MISS, 1f | 394 | wsr a2, depc # replace the saved a0 |
327 | addi a3, a3, -EXCCAUSE_DTLB_MISS | 395 | j 1f |
328 | bnez a3, .Lunrecoverable | ||
329 | 1: movi a3, fast_second_level_miss_double_kernel | ||
330 | jx a3 | ||
331 | #else | ||
332 | .equ .Lksp, .Lunrecoverable | ||
333 | #endif | ||
334 | 396 | ||
335 | /* Critical! We can't handle this situation. PANIC! */ | 397 | 2: |
398 | /* | ||
399 | * Restore a0 as saved by _WindowOverflow12(). | ||
400 | * | ||
401 | * FIXME: we really need a fixup handler for this L32E, | ||
402 | * for the extremely unlikely case where the overflow handler's | ||
403 | * reference thru a0 gets a hardware TLB refill that bumps out | ||
404 | * the (distinct, aliasing) TLB entry that mapped its prior | ||
405 | * references thru a13, and where our reference now thru a13 | ||
406 | * gets a 2nd-level miss exception (not hardware TLB refill). | ||
407 | */ | ||
336 | 408 | ||
337 | .extern unrecoverable_exception | 409 | l32e a2, a13, -16 |
410 | wsr a2, depc # replace the saved a0 | ||
411 | 1: | ||
412 | /* | ||
413 | * Restore WindowBase while leaving all address registers restored. | ||
414 | * We have to use ROTW for this, because WSR.WINDOWBASE requires | ||
415 | * an address register (which would prevent restore). | ||
416 | * | ||
417 | * Window Base goes from 0 ... 7 (Module 8) | ||
418 | * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s | ||
419 | */ | ||
420 | |||
421 | rsr a0, ps | ||
422 | extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH | ||
423 | rsr a2, windowbase | ||
424 | sub a0, a2, a0 | ||
425 | extui a0, a0, 0, 3 | ||
338 | 426 | ||
339 | .Lunrecoverable_fixup: | ||
340 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE | 427 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE |
341 | xsr a0, depc | 428 | xsr a3, excsave1 |
429 | beqi a0, 1, .L1pane | ||
430 | beqi a0, 3, .L3pane | ||
342 | 431 | ||
343 | .Lunrecoverable: | 432 | rsr a0, depc |
344 | rsr a3, excsave1 | 433 | rotw -2 |
345 | wsr a0, excsave1 | 434 | |
346 | movi a0, unrecoverable_exception | 435 | /* |
347 | callx0 a0 | 436 | * We are now in the user code's original window frame. |
437 | * Process the exception as a user exception as if it was | ||
438 | * taken by the user code. | ||
439 | * | ||
440 | * This is similar to the user exception vector, | ||
441 | * except that PT_DEPC isn't set to EXCCAUSE. | ||
442 | */ | ||
443 | 1: | ||
444 | xsr a3, excsave1 | ||
445 | wsr a2, depc | ||
446 | l32i a2, a3, EXC_TABLE_KSTK | ||
447 | s32i a0, a2, PT_AREG0 | ||
448 | rsr a0, exccause | ||
449 | |||
450 | s32i a0, a2, PT_DEPC | ||
451 | |||
452 | addx4 a0, a0, a3 | ||
453 | l32i a0, a0, EXC_TABLE_FAST_USER | ||
454 | xsr a3, excsave1 | ||
455 | jx a0 | ||
456 | |||
457 | .L1pane: | ||
458 | rsr a0, depc | ||
459 | rotw -1 | ||
460 | j 1b | ||
461 | |||
462 | .L3pane: | ||
463 | rsr a0, depc | ||
464 | rotw -3 | ||
465 | j 1b | ||
348 | 466 | ||
349 | .end literal_prefix | 467 | .end literal_prefix |
350 | 468 | ||
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index d8507f812f46..74a60c7e085e 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/io.h> | 25 | #include <asm/io.h> |
26 | #include <asm/page.h> | 26 | #include <asm/page.h> |
27 | #include <asm/pgalloc.h> | 27 | #include <asm/pgalloc.h> |
28 | #include <asm/ftrace.h> | ||
28 | #ifdef CONFIG_BLK_DEV_FD | 29 | #ifdef CONFIG_BLK_DEV_FD |
29 | #include <asm/floppy.h> | 30 | #include <asm/floppy.h> |
30 | #endif | 31 | #endif |