summaryrefslogtreecommitdiff
path: root/libcpu/ppc/ppc405/context_gcc.S
blob: f6a53dce3d6bd2b71c46d86e99f2e2ff6f6c4c5f (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "context.h"
#define SPRG0	0x110	/* Special Purpose Register General 0 */
#define SPRG1	0x111	/* Special Purpose Register General 1 */

    .globl rt_hw_interrupt_disable
    .globl rt_hw_interrupt_enable
    .globl rt_hw_context_switch
    .globl rt_hw_context_switch_to
    .globl rt_hw_context_switch_interrupt
    .globl rt_hw_systemcall_entry

/*
 * rt_base_t rt_hw_interrupt_disable();
 * return the interrupt status and disable interrupt
 */
#if 0
rt_hw_interrupt_disable:
    mfmsr   r3          /* Disable interrupts */
    li      r4,0
    ori     r4,r4,MSR_EE
    andc    r4,r4,r3
    SYNC                /* Some chip revs need this... */
    mtmsr   r4
    SYNC
    blr
#else
rt_hw_interrupt_disable:
    addis  r4, r0, 0xFFFD
    ori    r4, r4, 0x7FFF
    mfmsr  r3
    and    r4, r4, 3                                      /* Clear bits 14 and 16, corresponding to...   */
    mtmsr  r4                                            /* ...critical and non-critical interrupts     */
    blr
#endif

/*
 * void rt_hw_interrupt_enable(rt_base_t level);
 * restore interrupt
 */
rt_hw_interrupt_enable:
    mtmsr   r3
    SYNC
    blr

/*
 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
 * r3 --> from
 * r4 --> to
 *
 * r1: stack pointer
 */
rt_hw_systemcall_entry:
    mtspr   SPRG0,r3                            /* save r3 to SPRG0 */
    mtspr   SPRG1,r4                            /* save r4 to SPRG1 */

    lis     r3,rt_thread_switch_interrput_flag@h
    ori     r3,r3,rt_thread_switch_interrput_flag@l
    lwz     r4,0(r3)
    cmpi    cr0,0,r4,0x0                        /* whether is 0     */
    beq     _no_switch                          /* no switch, exit  */
    li      r4,0x0                              /* set rt_thread_switch_interrput_flag to 0 */
    stw     r4,0(r3)

    /* load from thread to r3 */
    lis     r3,rt_interrupt_from_thread@h       /* set rt_interrupt_from_thread */
    ori     r3,r3,rt_interrupt_from_thread@l
    lwz     r3,0(r3)

    cmpi    cr0,0,r3,0x0                        /* whether is 0 */
    beq     _restore                            /* it's first switch, goto _restore */

    /* save r1:sp to thread[from] stack pointer */
    subi    r1, r1, STACK_FRAME_SIZE
    stw     r1, 0(r3)

    /* restore r3, r4 from SPRG */
    mfspr   r3,SPRG0
    mfspr   r4,SPRG0

    /* save registers   */
    stw     r0,GPR0(r1)                         /* save general purpose registers 0    */
    stmw    r2,GPR2(r1)                         /* save general purpose registers 2-31 */

    mfusprg0 r0                                 /* save usprg0  */
    stw     r0,USPRG0(r1)
    mfcr    r0,                                 /* save cr      */
    stw     r0,CR(r1)
    mfxer   r0                                  /* save xer     */
    stw     r0,XER(r1)
    mfctr   r0                                  /* save ctr     */
    stw     r0,CTR(r1)
    mflr    r0                                  /* save lr      */
    stw     r0, LR(r1)

    mfsrr0  r0                                  /* save SRR0 and SRR1   */
    stw     r0,SRR0(r1)
    mfsrr1  r0
    stw     r0,SRR1(r1)

_restore:
    /* get thread[to] stack pointer */
    lis     r4,rt_interrupt_to_thread@h
    ori     r4,r4,rt_interrupt_to_thread@l
    lwz     r1,0(r4)
    lwz     r1,0(r1)

    lwz     r0,SRR1(r1)                         /* restore SRR1 and SRR0   */
    mtsrr1  r0
    lwz     r0,SRR0(r1)
    mtsrr0  r0

    lwz     r0,LR(r1)                           /* restore lr       */
    mtlr    r0
    lwz     r0,CTR(r1)                          /* restore ctr     */
    mtctr   r0
    lwz     r0,XER(r1)                          /* restore xer     */
    mtxer   r0
    lwz     r0,CR(r1)                           /* restore cr      */
    mtcr    r0
    lwz     r0,USPRG0(r1)                       /* restore usprg0  */
    // mtusprg0 r0

    lmw     r2, GPR2(r1)                        /* restore general register */
    lwz     r0,GPR0(r1)
    addi    r1, r1, STACK_FRAME_SIZE
    /* RFI will restore status register and thus the correct priority*/
    rfi

_no_switch:
    /* restore r3, r4 from SPRG */
    mfspr   r3,SPRG0
    mfspr   r4,SPRG0
    rfi

    /* void rt_hw_context_switch_to(to); */
    .globl rt_hw_context_switch_to
rt_hw_context_switch_to:
    /* set rt_thread_switch_interrput_flag = 1 */
    lis     r5,rt_thread_switch_interrput_flag@h
    ori     r5,r5,rt_thread_switch_interrput_flag@l
    li      r6, 0x01
    stw     r6,0(r5)

    /* set rt_interrupt_from_thread = 0 */
    lis     r5,rt_interrupt_from_thread@h
    ori     r5,r5,rt_interrupt_from_thread@l
    li      r6, 0x00
    stw     r6,0(r5)

    /* set rt_interrupt_from_thread = to */
    lis     r5,rt_interrupt_to_thread@h
    ori     r5,r5,rt_interrupt_to_thread@l
    stw     r3,0(r5)

    /* trigger a system call */
    sc

    blr

    /* void rt_hw_context_switch(from, to); */
    .globl rt_hw_context_switch
rt_hw_context_switch:
    /* compare rt_thread_switch_interrupt_flag and set it */
    lis     r5,rt_thread_switch_interrput_flag@h
    ori     r5,r5,rt_thread_switch_interrput_flag@l
    lwz     r6,0(r5)
    cmpi    cr0,0,r6,0x1                        /* whether is 1 */
    beq     _reswitch                           /* set already, goto _reswitch */
    li      r6,0x1                              /* set rt_thread_switch_interrput_flag to 1*/
    stw     r6,0(r5)

    /* set rt_interrupt_from_thread to 'from' */
    lis     r5,rt_interrupt_from_thread@h
    ori     r5,r5,rt_interrupt_from_thread@l
    stw     r3,0(r5)

_reswitch:
    /* set rt_interrupt_to_thread to 'to' */
    lis     r6,rt_interrupt_to_thread@h
    ori     r6,r6,rt_interrupt_to_thread@l
    stw     r4,0(r6)

    /* trigger a system call */
    sc

    blr

    .globl rt_hw_context_switch_interrupt
rt_hw_context_switch_interrupt:
    /* compare rt_thread_switch_interrupt_flag and set it */
    lis     r5,rt_thread_switch_interrput_flag@h
    ori     r5,r5,rt_thread_switch_interrput_flag@l
    lwz     r6,0(r5)
    cmpi    cr0,0,r6,0x1                        /* whether is 1 */
    beq     _int_reswitch                       /* set already, goto _reswitch */
    li      r6,0x1                              /* set rt_thread_switch_interrput_flag to 1*/
    stw     r6,0(r5)

    /* set rt_interrupt_from_thread to 'from' */
    lis     r5,rt_interrupt_from_thread@h
    ori     r5,r5,rt_interrupt_from_thread@l
    stw     r3,0(r5)

_int_reswitch:
    /* set rt_interrupt_to_thread to 'to' */
    lis     r6,rt_interrupt_to_thread@h
    ori     r6,r6,rt_interrupt_to_thread@l
    stw     r4,0(r6)

    blr