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 | |
| 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
| -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 |
