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
|
/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <sysdep.h>
#include <asm/errno.h>
#include <arch/spr_def.h>
#include <arch/abi.h>
#include "ucontext_i.h"
/* PL to return to via iret in setcontext */
#define RETURN_PL 0
/* int setcontext (const ucontext_t *ucp) */
.text
ENTRY (__setcontext)
FEEDBACK_ENTER(__setcontext)
/* See if this is a true signal context (flags == 0).
If so, restore by invoking rt_sigreturn(). */
#if UC_FLAGS_OFFSET != 0
# error "Add offset to r0 prior to load."
#endif
LD_PTR r10, r0
{
BEQZ r10, .Lsigreturn
addi r10, r10, -1 /* Confirm that it has value "1". */
}
BNEZ r10, .Lbadcontext
/* Save lr and r0 briefly on the stack and set the signal mask:
rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG / 8). */
{
ST sp, lr
ADDI_PTR r11, sp, -(2 * REGSIZE)
move r10, sp
}
ADDI_PTR sp, sp, -(3 * REGSIZE)
cfi_def_cfa_offset (3 * REGSIZE)
cfi_offset (lr, 0)
{
ST r11, r10
ADDI_PTR r10, sp, (2 * REGSIZE)
}
{
ST r10, r0
ADDLI_PTR r1, r0, UC_SIGMASK_OFFSET
}
cfi_offset (r0, -REGSIZE)
{
movei r3, _NSIG / 8
movei r2, 0
}
{
movei r0, SIG_SETMASK
moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigprocmask
}
swint1
ADDI_PTR r11, sp, 2 * REGSIZE /* Restore uc_context to r11. */
{
LD r11, r11
ADDI_PTR sp, sp, 3 * REGSIZE
}
cfi_def_cfa_offset (0)
LD lr, sp
{
ADDI_PTR r10, r11, UC_REG(0)
BNEZ r1, .Lsyscall_error
}
/* Restore the argument registers; note they will be random
unless makecontext() has been called. */
{ LD r0, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r1, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r2, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r3, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r4, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r5, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r6, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r7, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r8, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r9, r10; ADDLI_PTR r10, r10, UC_REG(30) - UC_REG(9) }
/* Restore the callee-saved GPRs. */
{ LD r30, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r31, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r32, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r33, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r34, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r35, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r36, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r37, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r38, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r39, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r40, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r41, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r42, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r43, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r44, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r45, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r46, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r47, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r48, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r49, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r50, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r51, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r52, r10; ADDI_PTR r10, r10, REGSIZE * 2 }
/* Skip tp since it must not change for a given thread. */
{ LD sp, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD lr, r10; ADDI_PTR r10, r10, REGSIZE }
{ LD r11, r10; ADDI_PTR r10, r10, REGSIZE }
/* Construct an iret context; we set ICS so we can validly load
EX_CONTEXT for iret without being interrupted halfway through. */
{
LD r12, r10
movei r13, 1
}
{
mtspr INTERRUPT_CRITICAL_SECTION, r13
shli r12, r12, SPR_EX_CONTEXT_0_1__ICS_SHIFT
}
{
mtspr EX_CONTEXT_0_0, r11
ori r12, r12, RETURN_PL
}
mtspr EX_CONTEXT_0_1, r12
iret
jrp lr /* keep the backtracer happy */
.Lsigreturn:
/* This is a context obtained from a signal handler.
Perform a full restore by pushing the context
passed onto a simulated signal frame on the stack
and call the signal return syscall as if a signal
handler exited normally. */
{
ADDLI_PTR sp, sp, -(C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE)
ADDLI_PTR r1, sp, -UC_SIZE
}
cfi_def_cfa_offset (C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE)
moveli r2, UC_SIZE / REGSIZE
0: {
LD r10, r0
ADDI_PTR r0, r0, REGSIZE
}
{
ST r1, r10
ADDI_PTR r1, r1, REGSIZE
addi r2, r2, -1
}
BNEZ r2, 0b
moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigreturn
swint1
/* Restore the stack and fall through to the error
path. Successful rt_sigreturn never returns to
its calling place. */
ADDLI_PTR sp, sp, (C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE)
cfi_def_cfa_offset (0)
.Lsyscall_error:
j SYSCALL_ERROR_NAME
.Lbadcontext:
{
movei r1, EINVAL
j SYSCALL_ERROR_NAME
}
END (__setcontext)
.hidden __setcontext
weak_alias (__setcontext, setcontext)
ENTRY (__startcontext)
FEEDBACK_ENTER(__startcontext)
BEQZ r30, 1f
{
move r0, r30
jal __setcontext
}
1: {
movei r0, 0
j HIDDEN_JUMPTARGET(exit)
}
END (__startcontext)
.hidden __startcontext
|