1/*
2 * Copyright 2013, winocm. <winocm@icloud.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *   Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 *
11 *   Redistributions in binary form must reproduce the above copyright notice, this
12 *   list of conditions and the following disclaimer in the documentation and/or
13 *   other materials provided with the distribution.
14 *
15 *   If you are going to use this software in any form that does not involve
16 *   releasing the source to this project or improving it, let me know beforehand.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * ARM context switching.
31 */
32
33#include <arm/arch.h>
34#include <arm/asm_help.h>
35#include <assym.s>
36#include <mach/arm/asm.h>
37
38/**
39 * Call_continuation
40 *
41 * Switch the current context to the thread continuation and terminate on return.
42 */
43EnterARM(Call_continuation)
44    /* Set the new stack pointer. */
45    LoadThreadRegister(r9)
46    ldr     sp, [r9, TH_PCB_ISS]
47
48    /* Zero out frame pointer */
49    mov     r7, #0
50
51    /* Set arguments */
52    mov     r6, r0
53    mov     r0, r1
54    mov     r1, r2
55
56    /* Branch to continuation. */
57    blx      r6
58
59    /* Terminate thread. */
60    mrc     p15, 0, r0, c13, c0, 4
61    blx     _thread_terminate
62    b       .
63
64/**
65 * Switch_context
66 *
67 * Switch the current processor context to that of the new thread.
68 * Does not switch r0-r3 function argument registers.
69 */
70EnterARM(Switch_context)
71    /* Switch context to the new thread and save the continuation. */
72    teq     r1, #0
73    strne   r1, [r0, TH_CONTINUATION]
74
75    /* Only store registers if there is a continuation */
76    ldreq   r3, [r0, TH_PCB_ISS]
77    addeq   r3, r3, #16
78    stmiaeq r3, {r4-lr}
79
80    /* Save current thread */
81    LOAD_ADDR(r4, CurrentThread)
82    str     r2, [r4]
83
84    /* Set old/new threads */
85    mcr     p15, 0, r2, c13, c0, 4
86
87    ldr     r3, [r2, MACHINE_THREAD_CTHREAD_SELF]
88    mcr     p15, 0, r3, c13, c0, 3
89
90    /* Load registers and go. */
91    ldr     r3, [r2, TH_PCB_ISS]
92    add     r3, r3, #16
93    ldmia   r3!, {r4-lr}
94    bx      lr
95
96/**
97 * machine_load_context
98 *
99 * Load the registers and prepare for a context switch.
100 */
101EnterARM(machine_load_context)
102    /* Save current thread */
103    LOAD_ADDR(r4, CurrentThread)
104    str     r0, [r4]
105
106    /* Set thread */
107    mcr     p15, 0, r0, c13, c0, 4
108
109    /* Set cthread value */
110    ldr     r1, [r0, MACHINE_THREAD_CTHREAD_SELF]
111    mrc     p15, 0, r2, c13, c0, 3
112
113    /* Load registers and go. */
114    ldr     r3, [r0, TH_PCB_ISS]
115    mov     r0, #0
116
117    add     r3, r3, #16
118    ldmia   r3!, {r4-lr}
119    bx      lr
120
121/**
122 * thread_syscall_return
123 */
124EnterARM(thread_syscall_return)
125    cpsid   i
126    LoadThreadRegister(r9)
127    ldr     r4, [r9, TH_PCB_USS]
128    str     r0, [r4]
129    b       thread_return_join
130
131/**
132 * thread_exception_return
133 *
134 * Used to bootstrap a user thread.
135 */
136EnterARM(thread_exception_return)
137EnterARM(thread_bootstrap_return)
138    /* Disable interrupts */
139    cpsid   i
140
141thread_return_join:
142    /* Check for pending ast */
143    mrc     p15, 0, r9, c13, c0, 4
144
145    ldr     r8, [r9, MACHINE_THREAD_CPU_DATA]
146    ldr     r5, [r8, CPU_PENDING_AST]
147
148    cmp     r5, #0
149    beq     return_to_user
150
151    /* There's an ast. */
152
153    mov     r0, r5
154    mov     r1, #1
155    blx     _ast_taken
156
157    b       _thread_exception_return
158
159return_to_user:
160    /* Restore registers */
161    LoadThreadRegister(r5)
162    ldr     sp, [r5, TH_PCB_USS]
163    ldr     r0, [sp, #0x40]
164
165    msr     spsr_cxsf, r0
166#ifdef _ARM_ARCH_7
167    clrex
168#endif
169    ldr     lr, [sp, #0x3C]
170
171    ldmfd   sp, {r0-lr}^
172    movs    pc, lr
173
174LOAD_ADDR_GEN_DEF(CurrentThread)
175