1/*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8#include <lk/asm.h>
9#include <arch/arm/cores.h>
10
11    /* context switch frame is as follows:
12     * lr
13     * r11
14     * r10
15     * r9
16     * r8
17     * r7
18     * r6
19     * r5
20     * r4
21     */
22/* arm_context_switch(addr_t *old_sp, addr_t new_sp) */
23FUNCTION(arm_context_switch)
24    /* save non callee trashed supervisor registers */
25    /* spsr and user mode registers are saved and restored in the iframe by exceptions.S */
26    push    { r4-r11, lr }
27
28    /* save old sp */
29    str     sp, [r0]
30
31    /* clear any exlusive locks that the old thread holds */
32#if ARM_ARCH_LEVEL >= 7
33    /* can clear it directly */
34    clrex
35#elif ARM_ARCH_LEVEL == 6
36    /* have to do a fake strex to clear it */
37    ldr     r0, =strex_spot
38    strex   r3, r2, [r0]
39#endif
40
41    /* load new regs */
42    mov     sp, r1
43    pop     { r4-r11, lr }
44    bx      lr
45
46.ltorg
47
48#if ARM_ARCH_LEVEL == 6
49.data
50strex_spot:
51    .word   0
52#endif
53
54.text
55
56FUNCTION(arm_save_mode_regs)
57    mrs     r1, cpsr
58
59    stmia   r0, { r13, r14 }^ /* usr */
60    add     r0, #8
61
62    cps     #0x11   /* fiq */
63    str     r13, [r0], #4
64    str     r14, [r0], #4
65
66    cps     #0x12   /* irq */
67    str     r13, [r0], #4
68    str     r14, [r0], #4
69
70    cps     #0x13   /* svc */
71    str     r13, [r0], #4
72    str     r14, [r0], #4
73
74    cps     #0x17   /* abt */
75    str     r13, [r0], #4
76    str     r14, [r0], #4
77
78    cps     #0x1b   /* und */
79    str     r13, [r0], #4
80    str     r14, [r0], #4
81
82    cps     #0x1f   /* sys */
83    str     r13, [r0], #4
84    str     r14, [r0], #4
85
86    msr     cpsr_c, r1
87
88    bx      lr
89
90.text
91
92/* void arm_chain_load(paddr_t entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) __NO_RETURN; */
93/* shut down the system, branching into the secondary system */
94FUNCTION(arm_chain_load)
95    /* shuffle the args around */
96    mov     r4, r0      /* r4 = entry point */
97    mov     r0, r1
98    mov     r1, r2
99    mov     r2, r3
100    ldr     r3, [sp]
101
102#if WITH_KERNEL_VM
103/* The MMU is initialized and running at this point, so we'll need to
104 * make sure we can disable it and continue to run. The caller should
105 * have built a identity map for us and branched to our identity mapping,
106 * so it will be safe to just disable the mmu and branch to the entry
107 * point in physical space.
108 */
109    /* Read SCTLR */
110    mrc     p15, 0, r12, c1, c0, 0
111
112    /* Turn off the MMU */
113    bic     r12, #0x1
114
115    /* Write back SCTLR */
116    mcr     p15, 0, r12, c1, c0, 0
117    isb
118
119#endif // WITH_KERNEL_VM
120
121    /* call the entry point */
122    bx      r4
123