aboutsummaryrefslogtreecommitdiffstats
path: root/roms/openbios/arch/sparc32/switch.S
blob: e4dbc9afbbd0fde4fa3a1de9cadcb2dae590b6da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#define __ASSEMBLY
#include "psr.h"
#include "asm/asi.h"
#include "cpustate.h"
#define ASI_BP ASI_M_BYPASS
#define REGWIN_SZ   0x40

        .globl    __switch_context, __switch_context_nosave, __exit_context, halt

        .text
        .align 4

/*
 * 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      %g1, [%sp - 0x260 + 0x14]
        st      %g2, [%sp - 0x260 + 0x18]
        st      %g3, [%sp - 0x260 + 0x1c]
        st      %g4, [%sp - 0x260 + 0x20]
        st      %g5, [%sp - 0x260 + 0x24]
        st      %g6, [%sp - 0x260 + 0x28]
        st      %g7, [%sp - 0x260 + 0x2c]

        mov     %sp, %g1
        add     %g1, -0x260, %g1
        
        SAVE_CPU_STATE(switch)

        /* Return PC value */
        mov     %o7, %g2
        add     %g2, 4, %g2
        st      %g2, [%sp - 0x260 + 0x250]

        /* swap context */
        set     __context, %g3
        ld      [%g3], %g2
        st      %g1, [%g3]
        mov     %g2, %g1
        
        ba      __set_context
         nop

__switch_context_nosave:
        FLUSH_ALL_KERNEL_WINDOWS
        
        set     __context, %g1
        ld      [%g1], %g1
        
__set_context:
        RESTORE_CPU_STATE(switch)
        
        /* Restore globals */
        mov     %g1, %g2
        add     %g2, 0x14, %g2
        st      %g2, [%sp - 96]
        
        ld      [%g1 + 0x18], %g2
        ld      [%g1 + 0x1c], %g3
        ld      [%g1 + 0x20], %g4
        ld      [%g1 + 0x24], %g5
        ld      [%g1 + 0x28], %g6
        ld      [%g1 + 0x2c], %g7

        /* Finally, load new %pc */
        ld      [%g1 + 0x250], %g1
        jmpl    %g1, %o7
         ld     [%sp - 96], %g1
        
__exit_context:
        /* Get back to the original context */
        ba    __switch_context
         nop