1#------------------------------------------------------------------------------
2#
3# Copyright (c) 2009-2013, ARM Ltd.  All rights reserved.
4# This program and the accompanying materials
5# are licensed and made available under the terms and conditions of the BSD License
6# which accompanies this distribution.  The full text of the license may be found at
7# http://opensource.org/licenses/bsd-license.php.
8#
9# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11#
12#------------------------------------------------------------------------------
13.text
14.p2align 3
15
16GCC_ASM_EXPORT(SetJump)
17GCC_ASM_EXPORT(InternalLongJump)
18
19#define GPR_LAYOUT                         \
20        REG_PAIR (x19, x20,  0);           \
21        REG_PAIR (x21, x22, 16);           \
22        REG_PAIR (x23, x24, 32);           \
23        REG_PAIR (x25, x26, 48);           \
24        REG_PAIR (x27, x28, 64);           \
25        REG_PAIR (x29, x30, 80);/*FP, LR*/ \
26        REG_ONE  (x16,      96) /*IP0*/
27
28#define FPR_LAYOUT                      \
29        REG_PAIR ( d8,  d9, 112);       \
30        REG_PAIR (d10, d11, 128);       \
31        REG_PAIR (d12, d13, 144);       \
32        REG_PAIR (d14, d15, 160);
33
34#/**
35#  Saves the current CPU context that can be restored with a call to LongJump() and returns 0.#
36#
37#  Saves the current CPU context in the buffer specified by JumpBuffer and returns 0.  The initial
38#  call to SetJump() must always return 0.  Subsequent calls to LongJump() cause a non-zero
39#  value to be returned by SetJump().
40#
41#  If JumpBuffer is NULL, then ASSERT().
42#  For IPF CPUs, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT().
43#
44#  @param  JumpBuffer    A pointer to CPU context buffer.
45#
46#**/
47#
48#UINTN
49#EFIAPI
50#SetJump (
51#  IN      BASE_LIBRARY_JUMP_BUFFER  *JumpBuffer  // X0
52#  );
53#
54ASM_PFX(SetJump):
55        mov     x16, sp // use IP0 so save SP
56#define REG_PAIR(REG1, REG2, OFFS)      stp REG1, REG2, [x0, OFFS]
57#define REG_ONE(REG1, OFFS)             str REG1, [x0, OFFS]
58        GPR_LAYOUT
59        FPR_LAYOUT
60#undef REG_PAIR
61#undef REG_ONE
62        mov     w0, #0
63        ret
64
65#/**
66#  Restores the CPU context that was saved with SetJump().#
67#
68#  Restores the CPU context from the buffer specified by JumpBuffer.
69#  This function never returns to the caller.
70#  Instead is resumes execution based on the state of JumpBuffer.
71#
72#  @param  JumpBuffer    A pointer to CPU context buffer.
73#  @param  Value         The value to return when the SetJump() context is restored.
74#
75#**/
76#VOID
77#EFIAPI
78#InternalLongJump (
79#  IN      BASE_LIBRARY_JUMP_BUFFER  *JumpBuffer,  // X0
80#  IN      UINTN                     Value         // X1
81#  );
82#
83ASM_PFX(InternalLongJump):
84#define REG_PAIR(REG1, REG2, OFFS)      ldp REG1, REG2, [x0, OFFS]
85#define REG_ONE(REG1, OFFS)             ldr REG1, [x0, OFFS]
86        GPR_LAYOUT
87        FPR_LAYOUT
88#undef REG_PAIR
89#undef REG_ONE
90        mov     sp, x16
91        cmp     w1, #0
92        mov     w0, #1
93        csel    w0, w1, w0, ne
94        // use br not ret, as ret is guaranteed to mispredict
95        br      x30
96
97ASM_FUNCTION_REMOVE_IF_UNREFERENCED
98