aarch64: Add GCS support for setcontext

Userspace ucontext needs to store GCSPR, it does not have to be
compatible with the kernel ucontext. For now we use the linux
struct gcs_context layout but only use the gcspr field from it.

Similar implementation to the longjmp code, supports switching GCS
if the target GCS is capped, and unwinding a continuous GCS to a
previous state.

Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Szabolcs Nagy 2023-02-24 16:29:32 +00:00 committed by Yury Khrustalev
parent 1cf59c2603
commit 9885d13b66
4 changed files with 83 additions and 9 deletions

View file

@ -83,9 +83,24 @@ ENTRY(__getcontext)
mrs x4, fpcr mrs x4, fpcr
str w4, [x3, oFPCR - oFPSR] str w4, [x3, oFPCR - oFPSR]
/* Write the termination context extension header. */
add x2, x2, #FPSIMD_CONTEXT_SIZE add x2, x2, #FPSIMD_CONTEXT_SIZE
/* Save the GCSPR. */
mov x16, 1 /* _CHKFEAT_GCS */
CHKFEAT_X16
tbnz x16, 0, L(gcs_done)
mov w3, #(GCS_MAGIC & 0xffff)
movk w3, #(GCS_MAGIC >> 16), lsl #16
str w3, [x2, #oHEAD + oMAGIC]
mov w3, #GCS_CONTEXT_SIZE
str w3, [x2, #oHEAD + oSIZE]
MRS_GCSPR (x4)
add x4, x4, 8 /* GCS state right after getcontext returns. */
str x4, [x2, #oGCSPR]
add x2, x2, #GCS_CONTEXT_SIZE
L(gcs_done):
/* Write the termination context extension header. */
str wzr, [x2, #oHEAD + oMAGIC] str wzr, [x2, #oHEAD + oMAGIC]
str wzr, [x2, #oHEAD + oSIZE] str wzr, [x2, #oHEAD + oSIZE]

View file

@ -130,6 +130,44 @@ ENTRY (__setcontext)
ldr w4, [x3, oFPCR - oFPSR] ldr w4, [x3, oFPCR - oFPSR]
msr fpcr, x4 msr fpcr, x4
/* Restore the GCS. */
mov x16, 1 /* _CHKFEAT_GCS */
CHKFEAT_X16
tbnz x16, 0, L(gcs_done)
/* Get target GCS from GCS context. */
ldr w1, [x2, #oHEAD + oSIZE]
add x2, x2, x1
mov w3, #(GCS_MAGIC & 0xffff)
movk w3, #(GCS_MAGIC >> 16), lsl #16
ldr w1, [x2, #oHEAD + oMAGIC]
cmp w1, w3
b.ne L(gcs_done)
ldr x3, [x2, #oGCSPR]
MRS_GCSPR (x2)
mov x4, x3
/* x2: GCSPR now. x3, x4: target GCSPR. x5, x6: tmp regs. */
L(gcs_scan):
cmp x2, x4
b.eq L(gcs_pop)
sub x4, x4, 8
/* Check for a cap token. */
ldr x5, [x4]
and x6, x4, 0xfffffffffffff000
orr x6, x6, 1
cmp x5, x6
b.ne L(gcs_scan)
L(gcs_switch):
add x2, x4, 8
GCSSS1 (x4)
GCSSS2 (xzr)
L(gcs_pop):
cmp x2, x3
b.eq L(gcs_done)
GCSPOPM (xzr)
add x2, x2, 8
b L(gcs_pop)
L(gcs_done):
2: 2:
ldr x16, [x0, oPC] ldr x16, [x0, oPC]
/* Restore arg registers. */ /* Restore arg registers. */

View file

@ -32,8 +32,15 @@ ENTRY(__swapcontext)
And set up x1 to become the return address of the caller, so we 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. */ can return there with a normal RET instead of an indirect jump. */
stp xzr, x30, [x0, oX0 + 0 * SZREG] stp xzr, x30, [x0, oX0 + 0 * SZREG]
/* With GCS, swapcontext calls are followed by BTI J, otherwise
we have to be compatible with old BTI enabled binaries. */
mov x16, 1 /* _CHKFEAT_GCS */
CHKFEAT_X16
tbz x16, 0, L(skip_x30_redirect)
/* Arrange the oucp context to return to 2f. */ /* Arrange the oucp context to return to 2f. */
adr x30, 2f adr x30, 2f
L(skip_x30_redirect):
stp x18, x19, [x0, oX0 + 18 * SZREG] stp x18, x19, [x0, oX0 + 18 * SZREG]
stp x20, x21, [x0, oX0 + 20 * SZREG] stp x20, x21, [x0, oX0 + 20 * SZREG]
@ -72,14 +79,27 @@ ENTRY(__swapcontext)
mrs x4, fpcr mrs x4, fpcr
str w4, [x3, #oFPCR - oFPSR] str w4, [x3, #oFPCR - oFPSR]
/* Write the termination context extension header. */
add x2, x2, #FPSIMD_CONTEXT_SIZE add x2, x2, #FPSIMD_CONTEXT_SIZE
/* Save the GCSPR. */
tbnz x16, 0, L(gcs_done)
mov w3, #(GCS_MAGIC & 0xffff)
movk w3, #(GCS_MAGIC >> 16), lsl #16
str w3, [x2, #oHEAD + oMAGIC]
mov w3, #GCS_CONTEXT_SIZE
str w3, [x2, #oHEAD + oSIZE]
MRS_GCSPR (x4)
add x4, x4, 8 /* GCSPR of the caller. */
str x4, [x2, #oGCSPR]
add x2, x2, #GCS_CONTEXT_SIZE
L(gcs_done):
/* Write the termination context extension header. */
str wzr, [x2, #oHEAD + oMAGIC] str wzr, [x2, #oHEAD + oMAGIC]
str wzr, [x2, #oHEAD + oSIZE] str wzr, [x2, #oHEAD + oSIZE]
/* Preserve ucp. */ /* Preserve ucp. */
mov x21, x1 mov x9, x1
/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask,
_NSIG8) */ _NSIG8) */
@ -93,12 +113,8 @@ ENTRY(__swapcontext)
svc 0 svc 0
cbnz x0, 1f cbnz x0, 1f
mov x22, x30 mov x0, x9
mov x0, x21 b JUMPTARGET (__setcontext)
bl JUMPTARGET (__setcontext)
mov x30, x22
RET
1: 1:
b C_SYMBOL_NAME(__syscall_error) b C_SYMBOL_NAME(__syscall_error)
2: 2:

View file

@ -43,3 +43,8 @@
#define oX21 (oX0 + 21*8) #define oX21 (oX0 + 21*8)
#define oFP (oX0 + 29*8) #define oFP (oX0 + 29*8)
#define oLR (oX0 + 30*8) #define oLR (oX0 + 30*8)
/* Use kernel layout for saving GCSPR in ucontext. */
#define GCS_MAGIC 0x47435300
#define GCS_CONTEXT_SIZE 32
#define oGCSPR 8