| #define __ASSEMBLY |
| #include "psr.h" |
| #include "asm/asi.h" |
| #define ASI_BP ASI_M_BYPASS |
| #define REGWIN_SZ 0x40 |
| |
| .globl __switch_context, __switch_context_nosave, __exit_context, halt |
| |
| .text |
| .align 4 |
| |
| #define STACKFRAME_SZ 0x60 |
| |
| /* These are just handy. */ |
| #define _SV save %sp, -STACKFRAME_SZ, %sp |
| #define _RS restore |
| |
| #define FLUSH_ALL_KERNEL_WINDOWS \ |
| _SV; _SV; _SV; _SV; _SV; _SV; _SV; \ |
| _RS; _RS; _RS; _RS; _RS; _RS; _RS; |
| |
| /* |
| * Switch execution context |
| * This saves registers in the stack, then |
| * switches the stack, and restores everything from the new stack. |
| * This function takes no argument. New stack pointer is |
| * taken from global variable __context, and old stack pointer |
| * is also saved to __context. This way we can just jump to |
| * this routine to get back to the original context. |
| */ |
| |
| __switch_context: |
| FLUSH_ALL_KERNEL_WINDOWS |
| /* Save everything in stack */ |
| st %fp, [%fp + 120 -144] |
| add %fp, -144, %fp |
| st %g1, [%fp + 4] |
| st %g2, [%fp + 8] |
| st %g3, [%fp + 12] |
| st %g4, [%fp + 16] |
| st %g5, [%fp + 20] |
| st %g6, [%fp + 24] |
| st %g7, [%fp + 28] |
| |
| st %o0, [%fp + 32] |
| st %o1, [%fp + 36] |
| st %o2, [%fp + 40] |
| st %o3, [%fp + 44] |
| st %o4, [%fp + 48] |
| st %o5, [%fp + 52] |
| st %sp, [%fp + 56] |
| st %o7, [%fp + 60] |
| |
| st %l0, [%fp + 64] |
| st %l1, [%fp + 68] |
| st %l2, [%fp + 72] |
| st %l3, [%fp + 76] |
| st %l4, [%fp + 80] |
| st %l5, [%fp + 84] |
| st %l6, [%fp + 88] |
| st %l7, [%fp + 92] |
| |
| st %i0, [%fp + 96] |
| st %i1, [%fp + 100] |
| st %i2, [%fp + 104] |
| st %i3, [%fp + 108] |
| st %i4, [%fp + 112] |
| st %i5, [%fp + 116] |
| st %i7, [%fp + 124] |
| |
| /* ctx->return_address: Return to caller */ |
| st %o7, [%fp + 128] |
| |
| /* Interrupts are not allowed... */ |
| |
| /* Turn on Supervisor, EnableFloating, and all the PIL bits. |
| * Also puts us in register window zero with traps off. |
| */ |
| #if 0 |
| set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 |
| wr %g2, 0x0, %psr |
| #endif |
| set __context, %g1 |
| /* Swap ctx pointer with %fp and jump*/ |
| ba __set_context |
| swap [%g1], %fp |
| __switch_context_nosave: |
| set __context, %g1 |
| /* load %fp from ctx pointer */ |
| ld [%g1], %fp |
| __set_context: |
| /* Load all registers */ |
| /* offset 0: %g0, no need to load */ |
| ld [%fp + 4], %g1 |
| ld [%fp + 8], %g2 |
| ld [%fp + 12], %g3 |
| ld [%fp + 16], %g4 |
| ld [%fp + 20], %g5 |
| ld [%fp + 24], %g6 |
| ld [%fp + 28], %g7 |
| |
| /* offset 32: %o0, loaded from ctx->param */ |
| ld [%fp + 36], %o1 |
| ld [%fp + 40], %o2 |
| ld [%fp + 44], %o3 |
| ld [%fp + 48], %o4 |
| ld [%fp + 52], %o5 |
| ld [%fp + 56], %sp |
| /* offset 60: %o7, loaded from ctx->return_addr */ |
| |
| ld [%fp + 64], %l0 |
| ld [%fp + 68], %l1 |
| ld [%fp + 72], %l2 |
| ld [%fp + 76], %l3 |
| ld [%fp + 80], %l4 |
| ld [%fp + 84], %l5 |
| ld [%fp + 88], %l6 |
| ld [%fp + 92], %l7 |
| |
| ld [%fp + 96], %i0 |
| ld [%fp + 100], %i1 |
| ld [%fp + 104], %i2 |
| ld [%fp + 108], %i3 |
| ld [%fp + 112], %i4 |
| ld [%fp + 116], %i5 |
| ld [%fp + 124], %i7 |
| |
| /* ctx->return_addr */ |
| ld [%fp + 136], %o7 |
| |
| /* ctx->param */ |
| ld [%fp + 140], %o0 |
| |
| /* ctx->pc, save %g1 to %y and load to %g1 */ |
| mov %g1, %y |
| ld [%fp + 128], %g1 |
| /* %fp last */ |
| ld [%fp + 120], %fp |
| /* Finally, get the new %pc from %g1 and restore %g1*/ |
| jmp %g1 |
| mov %y, %g1 |
| |
| FLUSH_ALL_KERNEL_WINDOWS |
| __exit_context: |
| /* Get back to the original context */ |
| call __switch_context |
| nop |
| |
| /* We get here if the other context attempt to switch to this |
| * dead context. This should not happen. */ |
| |
| halt: |
| b halt |
| nop |