From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1944) id 7069F3851503; Thu, 27 Oct 2022 13:57:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7069F3851503 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666879051; bh=n+01dR9+V0KzipahDtIm+ORqA/N6BP2TZdXhZtR9l1Y=; h=From:To:Subject:Date:From; b=OonUiipJyMrxwv4l/HSYxNz+7ew3ySSLawVoY3xtpZZDyK7sftIxvKTqgW3DsFMy7 DS0r8s621m8jguN6lTsxfEVFS6cMvHqury9LwxHf4jlY9JgT63sisWaSks1m+RLZt7 esOh4TfyW/dQnRs9BxpYGrNY4Ajx33VXzoXPbZ/Y= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Szabolcs Nagy To: glibc-cvs@sourceware.org Subject: [glibc/arm/morello/main] aarch64: morello: add purecap ucontext support X-Act-Checkin: glibc X-Git-Author: Carlos Eduardo Seo X-Git-Refname: refs/heads/arm/morello/main X-Git-Oldrev: 87a680a748e15c9cbb60135760c3fa671feeb797 X-Git-Newrev: 45f35bca7d80322d25f16b4794f812f2e9c7f936 Message-Id: <20221027135731.7069F3851503@sourceware.org> Date: Thu, 27 Oct 2022 13:57:21 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=45f35bca7d80322d25f16b4794f812f2e9c7f936 commit 45f35bca7d80322d25f16b4794f812f2e9c7f936 Author: Carlos Eduardo Seo Date: Thu May 27 17:49:20 2021 -0300 aarch64: morello: add purecap ucontext support Adjust ucontext layout for purecap ABI and add make/get/set/swapcontext implementations accordingly. Note: mcontext layout follows the linux sigcontext struct, in userspace *context functions rely on the c registers stored in the extension area and ignore the mcontext fields for x registers. Diff: --- sysdeps/unix/sysv/linux/aarch64/bits/procfs.h | 5 + .../unix/sysv/linux/aarch64/morello/getcontext.S | 121 +++++++++++++++++++ .../unix/sysv/linux/aarch64/morello/makecontext.c | 80 +++++++++++++ .../unix/sysv/linux/aarch64/morello/setcontext.S | 133 +++++++++++++++++++++ .../unix/sysv/linux/aarch64/morello/swapcontext.S | 120 +++++++++++++++++++ sysdeps/unix/sysv/linux/aarch64/sys/ucontext.h | 4 + sysdeps/unix/sysv/linux/aarch64/sys/user.h | 10 ++ .../unix/sysv/linux/aarch64/ucontext-internal.h | 5 + sysdeps/unix/sysv/linux/aarch64/ucontext_i.sym | 15 +++ 9 files changed, 493 insertions(+) diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/procfs.h b/sysdeps/unix/sysv/linux/aarch64/bits/procfs.h index 154fb95e66..596b95e333 100644 --- a/sysdeps/unix/sysv/linux/aarch64/bits/procfs.h +++ b/sysdeps/unix/sysv/linux/aarch64/bits/procfs.h @@ -33,3 +33,8 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; /* Register set for the floating-point registers. */ typedef struct user_fpsimd_struct elf_fpregset_t; + +#ifdef __CHERI_PURE_CAPABILITY__ +/* Register set for the capability registers. */ +typedef struct user_morello_struct elf_cregset_t; +#endif diff --git a/sysdeps/unix/sysv/linux/aarch64/morello/getcontext.S b/sysdeps/unix/sysv/linux/aarch64/morello/getcontext.S new file mode 100644 index 0000000000..217ca28285 --- /dev/null +++ b/sysdeps/unix/sysv/linux/aarch64/morello/getcontext.S @@ -0,0 +1,121 @@ +/* Save current context. + + Copyright (C) 2009-2022 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + 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 + . */ + +#include +#include "ucontext_i.h" +#include "ucontext-internal.h" + +/* int getcontext (ucontext_t *ucp) + + Returns 0 on success -1 and errno on failure. + */ + + .text + +ENTRY(__getcontext) + /* For Morello, we will save only the capability registers. These are saved + in a special area in the context extension block after the FPSIMD + context. */ + add c9, c0, #oEXTENSION + FPSIMD_CONTEXT_SIZE + + /* Write the context extension morello header. */ + mov w3, #(MORELLO_MAGIC & 0xffff) + movk w3, #(MORELLO_MAGIC >> 16), lsl #16 + str w3, [c9, #oCHEAD + oMAGIC] + mov w3, #MORELLO_CONTEXT_SIZE + str w3, [c9, #oCHEAD + oSIZE] + + add c10, c9, #oC0 + /* The saved context will return to the getcontext() call point + with a return value of 0 */ + str czr, [c10, 0 * SZCREG] + + stp c18, c19, [c10, 18 * SZCREG] + stp c20, c21, [c10, 20 * SZCREG] + stp c22, c23, [c10, 22 * SZCREG] + stp c24, c25, [c10, 24 * SZCREG] + stp c26, c27, [c10, 26 * SZCREG] + stp c28, c29, [c10, 28 * SZCREG] + str c30, [c10, 30 * SZCREG] + + /* Place LR into the saved PC, this will ensure that when + switching to this saved context with setcontext() control + will pass back to the caller of getcontext(), we have + already arrange to return the appropriate return value in x0 + above. */ + str c30, [c9, oPCC] + + /* Save the current CSP */ + mov c2, csp + str c2, [c9, oCSP] + + /* Initialize the pstate. */ + str xzr, [c0, oPSTATE] + + /* Figure out where to place the first context extension + block. */ + add c2, c0, #oEXTENSION + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [c2, #oHEAD + oMAGIC] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [c2, #oHEAD + oSIZE] + + /* Fill in the FP SIMD context. */ + add c3, c2, #oV0 + 8 * SZVREG + stp q8, q9, [c3], # 2 * SZVREG + stp q10, q11, [c3], # 2 * SZVREG + stp q12, q13, [c3], # 2 * SZVREG + stp q14, q15, [c3], # 2 * SZVREG + + add c3, c2, oFPSR + + mrs x4, fpsr + str w4, [c3] + + mrs x4, fpcr + str w4, [c3, oFPCR - oFPSR] + + /* Write the termination context extension header after the Morello + context. */ + add c2, c2, #FPSIMD_CONTEXT_SIZE + MORELLO_CONTEXT_SIZE + str wzr, [c2, #oHEAD + oMAGIC] + str wzr, [c2, #oHEAD + oSIZE] + + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add c2, c0, #UCONTEXT_SIGMASK + mov x0, SIG_BLOCK + mov x1, 0 + mov x3, _NSIG8 + mov x8, SYS_ify (rt_sigprocmask) + svc 0 + cbnz x0, 1f + + /* Return 0 for success */ + mov x0, 0 + RET +1: + b C_SYMBOL_NAME(__syscall_error) + + PSEUDO_END (__getcontext) +weak_alias (__getcontext, getcontext) diff --git a/sysdeps/unix/sysv/linux/aarch64/morello/makecontext.c b/sysdeps/unix/sysv/linux/aarch64/morello/makecontext.c new file mode 100644 index 0000000000..3bbfe85887 --- /dev/null +++ b/sysdeps/unix/sysv/linux/aarch64/morello/makecontext.c @@ -0,0 +1,80 @@ +/* Create new context. + Copyright (C) 2002-2022 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + 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 + . */ + +#include +#include +#include +#include +#include +#include +#include "ucontext-internal.h" + +/* makecontext sets up a stack and the registers for the + user context. The stack looks like this: + + +-----------------------+ + | padding as required | + +-----------------------+ + sp -> | parameter 7-n | + +-----------------------+ + + The registers are set up like this: + %c0 .. %c7: parameter 1 to 8 + %c19 : uc_link + %csp : stack pointer. +*/ + +void +__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + extern void __startcontext (void); + uint64_t *sp; + va_list ap; + int i; + struct morello_context *c_context; + + sp = (uint64_t *) + ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + + /* Allocate stack arguments. */ + sp -= argc < 8 ? 0 : argc - 8; + + /* Keep the stack aligned. */ + sp = (uint64_t *) (((uintptr_t) sp) & -16L); + + c_context = (void *) (ucp->uc_mcontext.__reserved + + sizeof (struct fpsimd_context)); + + c_context->cregs[19] = (uintptr_t) ucp->uc_link; + c_context->csp = (uintptr_t) sp; + c_context->pcc = (uintptr_t) func; + c_context->cregs[29] = (uintptr_t) 0; + c_context->cregs[30] = (uintptr_t) &__startcontext; + + va_start (ap, argc); + for (i = 0; i < argc; ++i) + if (i < 8) + c_context->cregs[i] = va_arg (ap, uint64_t); + else + sp[i - 8] = va_arg (ap, uint64_t); + + va_end (ap); +} + +weak_alias (__makecontext, makecontext) diff --git a/sysdeps/unix/sysv/linux/aarch64/morello/setcontext.S b/sysdeps/unix/sysv/linux/aarch64/morello/setcontext.S new file mode 100644 index 0000000000..3556d783fc --- /dev/null +++ b/sysdeps/unix/sysv/linux/aarch64/morello/setcontext.S @@ -0,0 +1,133 @@ +/* Set current context. + + Copyright (C) 2009-2022 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + 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 + . */ + +#include +#include "ucontext_i.h" +#include "ucontext-internal.h" + +/* int __setcontext (const ucontext_t *ucp) + + Restores the machine context in UCP and thereby resumes execution + in that context. + + This implementation is intended to be used for *synchronous* context + switches only. Therefore, it does not have to restore anything + other than the PRESERVED state. */ + + .text + +ENTRY (__setcontext) + /* Save a copy of UCP. */ + mov c9, c0 + + /* Set the signal mask with + rt_sigprocmask (SIG_SETMASK, mask, NULL, _NSIG/8). */ + mov x0, #SIG_SETMASK + add c1, c9, #UCONTEXT_SIGMASK + mov x2, #0 + mov x3, #_NSIG8 + mov x8, SYS_ify (rt_sigprocmask) + svc 0 + cbz x0, 1f + b C_SYMBOL_NAME (__syscall_error) +1: + /* Restore the capability registers. For Morello, they are saved after the + FPSIMD context. */ + mov c0, c9 + cfi_def_cfa (c0, 0) + cfi_offset (c18, oC0 + 18 * SZCREG) + cfi_offset (c19, oC0 + 19 * SZCREG) + cfi_offset (c20, oC0 + 20 * SZCREG) + cfi_offset (c21, oC0 + 21 * SZCREG) + cfi_offset (c22, oC0 + 22 * SZCREG) + cfi_offset (c23, oC0 + 23 * SZCREG) + cfi_offset (c24, oC0 + 24 * SZCREG) + cfi_offset (c25, oC0 + 25 * SZCREG) + cfi_offset (c26, oC0 + 26 * SZCREG) + cfi_offset (c27, oC0 + 27 * SZCREG) + cfi_offset (c28, oC0 + 28 * SZCREG) + cfi_offset (c29, oC0 + 29 * SZCREG) + cfi_offset (c30, oC0 + 30 * SZCREG) + + cfi_offset ( d8, oV0 + 8 * SZVREG) + cfi_offset ( d9, oV0 + 9 * SZVREG) + cfi_offset (d10, oV0 + 10 * SZVREG) + cfi_offset (d11, oV0 + 11 * SZVREG) + cfi_offset (d12, oV0 + 12 * SZVREG) + cfi_offset (d13, oV0 + 13 * SZVREG) + cfi_offset (d14, oV0 + 14 * SZVREG) + cfi_offset (d15, oV0 + 15 * SZVREG) + + add c9, c0, #oEXTENSION + FPSIMD_CONTEXT_SIZE + add c10, c9, #oC0 + ldp c18, c19, [c10, 18 * SZCREG] + ldp c20, c21, [c10, 20 * SZCREG] + ldp c22, c23, [c10, 22 * SZCREG] + ldp c24, c25, [c10, 24 * SZCREG] + ldp c26, c27, [c10, 26 * SZCREG] + ldp c28, c29, [c10, 28 * SZCREG] + ldr c30, [c10, 30 * SZCREG] + ldr c2, [c9, oCSP] + mov csp, c2 + + /* Check for FP SIMD context. We don't support restoring + contexts created by the kernel, so this context must have + been created by getcontext. Hence we can rely on the + first extension block being the FP SIMD context. */ + add c2, c0, #oEXTENSION + + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + ldr w1, [c2, #oHEAD + oMAGIC] + cmp w1, w3 + b.ne 2f + + /* Restore the FP SIMD context. */ + add c3, c2, #oV0 + 8 * SZVREG + ldp q8, q9, [c3], #2 * SZVREG + ldp q10, q11, [c3], #2 * SZVREG + ldp q12, q13, [c3], #2 * SZVREG + ldp q14, q15, [c3], #2 * SZVREG + + add c3, c2, oFPSR + + ldr w4, [c3] + msr fpsr, x4 + + ldr w4, [c3, oFPCR - oFPSR] + msr fpcr, x4 + +2: + ldr c16, [c9, oPCC] + /* Restore arg registers. */ + ldp c2, c3, [c10, 2 * SZCREG] + ldp c4, c5, [c10, 4 * SZCREG] + ldp c6, c7, [c10, 6 * SZCREG] + ldp c0, c1, [c10, 0 * SZCREG] + /* Jump to the new pc value. */ + br c16 +PSEUDO_END (__setcontext) +weak_alias (__setcontext, setcontext) + +ENTRY (__startcontext) + mov c0, c19 + cbnz x0, __setcontext +1: b HIDDEN_JUMPTARGET (exit) +END (__startcontext) diff --git a/sysdeps/unix/sysv/linux/aarch64/morello/swapcontext.S b/sysdeps/unix/sysv/linux/aarch64/morello/swapcontext.S new file mode 100644 index 0000000000..90e4eca413 --- /dev/null +++ b/sysdeps/unix/sysv/linux/aarch64/morello/swapcontext.S @@ -0,0 +1,120 @@ +/* Modify saved context. + + Copyright (C) 2009-2022 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + 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 + . */ + +#include + +#include "ucontext_i.h" +#include "ucontext-internal.h" + +/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ + + .text +ENTRY(__swapcontext) + /* Set the value returned when swapcontext() returns in this context. + And set up x1 to become the return address of the caller, so we + can return there with a normal RET instead of an indirect jump. */ + + /* For Morello, the capability registers are located in after the FPSIMD + context. */ + add c9, c0, #oEXTENSION + FPSIMD_CONTEXT_SIZE + + /* Write the context extension morello header. */ + mov w3, #(MORELLO_MAGIC & 0xffff) + movk w3, #(MORELLO_MAGIC >> 16), lsl #16 + str w3, [c9, #oCHEAD + oMAGIC] + mov w3, #MORELLO_CONTEXT_SIZE + str w3, [c9, #oCHEAD + oSIZE] + + add c10, c9, #oC0 + stp czr, c30, [c10, 0 * SZCREG] + /* Arrange the oucp context to return to 2f. */ + adr c30, 2f + + stp c18, c19, [c10, 18 * SZCREG] + stp c20, c21, [c10, 20 * SZCREG] + stp c22, c23, [c10, 22 * SZCREG] + stp c24, c25, [c10, 24 * SZCREG] + stp c26, c27, [c10, 26 * SZCREG] + stp c28, c29, [c10, 28 * SZCREG] + str c30, [c10, 30 * SZCREG] + str c30, [c9, oPCC] + mov c11, csp + str c11, [c9, oCSP] + + /* Figure out where to place the fpsimd context extension + block. */ + add c9, c0, #oEXTENSION + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [c9, #oHEAD + oMAGIC] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [c9, #oHEAD + oSIZE] + + /* Fill in the FP SIMD context. */ + add c10, c9, #oV0 + 8 * SZVREG + stp q8, q9, [c10], #2 * SZVREG + stp q10, q11, [c10], #2 * SZVREG + stp q12, q13, [c10], #2 * SZVREG + stp q14, q15, [c10], #2 * SZVREG + + add c10, c9, #oFPSR + mrs x4, fpsr + str w4, [c10, #oFPSR - oFPSR] + mrs x4, fpcr + str w4, [c10, #oFPCR - oFPSR] + + /* Write the termination context extension header after the Morello + context. */ + add c9, c9, #FPSIMD_CONTEXT_SIZE + MORELLO_CONTEXT_SIZE + str wzr, [c9, #oHEAD + oMAGIC] + str wzr, [c9, #oHEAD + oSIZE] + + /* Preserve ucp. */ + mov c11, c1 + + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, + _NSIG8) */ + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add c2, c0, #UCONTEXT_SIGMASK + mov x0, SIG_BLOCK + mov x1, 0 + mov x3, _NSIG8 + mov x8, SYS_ify (rt_sigprocmask) + svc 0 + cbnz x0, 1f + + mov c15, c30 + mov c0, c11 + bl JUMPTARGET (__setcontext) + mov c30, c15 + RET + +1: + b C_SYMBOL_NAME(__syscall_error) +2: + /* The oucp context is restored here via an indirect branch, + x1 must be restored too which has the real return address. */ + mov c30, c1 + RET +PSEUDO_END (__swapcontext) +weak_alias (__swapcontext, swapcontext) diff --git a/sysdeps/unix/sysv/linux/aarch64/sys/ucontext.h b/sysdeps/unix/sysv/linux/aarch64/sys/ucontext.h index fe91db68e8..cd39a2272b 100644 --- a/sysdeps/unix/sysv/linux/aarch64/sys/ucontext.h +++ b/sysdeps/unix/sysv/linux/aarch64/sys/ucontext.h @@ -43,6 +43,10 @@ typedef elf_gregset_t gregset_t; /* Structure to describe FPU registers. */ typedef elf_fpregset_t fpregset_t; +# ifdef __CHERI_PURE_CAPABILITY__ +/* Structure to describe capability registers. */ +typedef elf_cregset_t cregset_t; +# endif #endif /* Context to describe whole processor state. This only describes diff --git a/sysdeps/unix/sysv/linux/aarch64/sys/user.h b/sysdeps/unix/sysv/linux/aarch64/sys/user.h index 32fbfd5f1a..e228838bc7 100644 --- a/sysdeps/unix/sysv/linux/aarch64/sys/user.h +++ b/sysdeps/unix/sysv/linux/aarch64/sys/user.h @@ -34,4 +34,14 @@ struct user_fpsimd_struct unsigned int fpcr; }; +# ifdef __CHERI_PURE_CAPABILITY__ +struct user_morello_struct +{ + __uintcap_t cregs[31]; + __uintcap_t csp; + __uintcap_t rcsp; + __uintcap_t pcc; +}; +# endif + #endif diff --git a/sysdeps/unix/sysv/linux/aarch64/ucontext-internal.h b/sysdeps/unix/sysv/linux/aarch64/ucontext-internal.h index 685d41ca04..429a4c1035 100644 --- a/sysdeps/unix/sysv/linux/aarch64/ucontext-internal.h +++ b/sysdeps/unix/sysv/linux/aarch64/ucontext-internal.h @@ -23,6 +23,11 @@ /* Size of an X regiser in bytes. */ #define SZREG 8 +#ifdef __CHERI_PURE_CAPABILITY__ +/* Size of a C register in bytes. */ +# define SZCREG 16 +#endif + /* Size of a V register in bytes. */ #define SZVREG 16 diff --git a/sysdeps/unix/sysv/linux/aarch64/ucontext_i.sym b/sysdeps/unix/sysv/linux/aarch64/ucontext_i.sym index ab3930c173..78022326af 100644 --- a/sysdeps/unix/sysv/linux/aarch64/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/aarch64/ucontext_i.sym @@ -18,6 +18,9 @@ RT_SIGFRAME_UCONTEXT rt_sigframe (uc) RT_SIGFRAME_SIZE sizeof (struct kernel_rt_sigframe) FPSIMD_CONTEXT_SIZE sizeof (struct fpsimd_context) +#ifdef __CHERI_PURE_CAPABILITY__ +MORELLO_CONTEXT_SIZE sizeof (struct morello_context) +#endif #define ucontext(member) offsetof (ucontext_t, member) #define stack(member) ucontext (uc_stack.member) @@ -53,3 +56,15 @@ oMAGIC aarch64_ctx (magic) oSIZE aarch64_ctx (size) FPSIMD_MAGIC + +#ifdef __CHERI_PURE_CAPABILITY__ +#define morello_context(member) offsetof (struct morello_context, member) + +oCHEAD morello_context (head) +oC0 morello_context (cregs) +oCSP morello_context (csp) +oRCSP morello_context (rcsp) +oPCC morello_context (pcc) + +MORELLO_MAGIC +#endif