The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=81f07332c03fd2ac6efa8e15b1659a573d250329

commit 81f07332c03fd2ac6efa8e15b1659a573d250329
Author:     Harry Moulton <harry.moul...@arm.com>
AuthorDate: 2025-07-31 14:10:57 +0000
Commit:     Andrew Turner <and...@freebsd.org>
CommitDate: 2025-07-31 14:27:06 +0000

    arm64: tidy up Top-Byte-Ignore (TBI) in the kernel
    
    In preparation for TBI to be enabled for processes from 15.0 we need
    to clean up copying data between userspace and the kernel. These
    functions will check the address is within the valid userspace range,
    however as the userspace and kernel ranges may overlap when TBI is
    enabled we need to mask off the top 8 bits.
    
    Processes not using TBI are unaffected as the hardware will still
    check all bits in the address, however this will happen at the first
    load/store instruction.
    
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D49119
---
 sys/arm64/arm64/copyinout.S | 18 ++++++++++++++++--
 sys/arm64/arm64/support.S   |  9 ++++++++-
 sys/arm64/include/vmparam.h |  3 +++
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/sys/arm64/arm64/copyinout.S b/sys/arm64/arm64/copyinout.S
index 26dd0b4cf14f..e41c4b5f6734 100644
--- a/sys/arm64/arm64/copyinout.S
+++ b/sys/arm64/arm64/copyinout.S
@@ -37,7 +37,14 @@
 #include "assym.inc"
 
 .macro check_user_access user_arg, size_arg, bad_access_func
-       adds    x6, x\user_arg, x\size_arg
+       /*
+        * TBI is enabled from 15.0. Clear the top byte of the userspace
+        * address before checking whether it's within the given limit.
+        * The later load/store instructions will fault if TBI is disabled
+        * for the current process.
+        */
+       and     x6, x\user_arg, #(~TBI_ADDR_MASK)
+       adds    x6, x6, x\size_arg
        b.cs    \bad_access_func
        ldr     x7, =VM_MAXUSER_ADDRESS
        cmp     x6, x7
@@ -100,13 +107,20 @@ ENTRY(copyinstr)
        adr     x6, copyio_fault /* Get the handler address */
        SET_FAULT_HANDLER(x6, x7) /* Set the handler */
 
+       /*
+        *  As in check_user_access mask off the TBI bits for the cmp
+        * instruction. The load will fail trap if TBI is disabled, but we
+        * need to check the address didn't wrap.
+        */
+       and     x6, x0, #(~TBI_ADDR_MASK)
        ldr     x7, =VM_MAXUSER_ADDRESS
-1:     cmp     x0, x7
+1:     cmp     x6, x7
        b.cs    copyio_fault
        ldtrb   w4, [x0]        /* Load from uaddr */
        add     x0, x0, #1      /* Next char */
        strb    w4, [x1], #1    /* Store in kaddr */
        add     x5, x5, #1      /* count++ */
+       add     x6, x6, #1      /* Increment masked address */
        cbz     w4, 2f          /* Break when NUL-terminated */
        sub     x2, x2, #1      /* len-- */
        cbnz    x2, 1b
diff --git a/sys/arm64/arm64/support.S b/sys/arm64/arm64/support.S
index 2d067c7f7730..bf6fc931e4b0 100644
--- a/sys/arm64/arm64/support.S
+++ b/sys/arm64/arm64/support.S
@@ -39,8 +39,15 @@
 #include "assym.inc"
 
 .macro check_user_access user_arg, limit, bad_addr_func
+       /*
+        * TBI is enabled from 15.0. Clear the top byte of the userspace
+        * address before checking whether it's within the given limit.
+        * The later load/store instructions will fault if TBI is disabled
+        * for the current process.
+        */
+       and     x6, x\user_arg, #(~TBI_ADDR_MASK)
        ldr     x7, =(\limit)
-       cmp     x\user_arg, x7
+       cmp     x6, x7
        b.cs    \bad_addr_func
 .endm
 
diff --git a/sys/arm64/include/vmparam.h b/sys/arm64/include/vmparam.h
index db3af1881282..c30ca1b2bff4 100644
--- a/sys/arm64/include/vmparam.h
+++ b/sys/arm64/include/vmparam.h
@@ -211,6 +211,9 @@
 /* The address bits that hold a pointer authentication code */
 #define        PAC_ADDR_MASK           (0xff7f000000000000UL)
 
+/* The top-byte ignore address bits */
+#define        TBI_ADDR_MASK           0xff00000000000000UL
+
 /* If true addr is in the kernel address space */
 #define        ADDR_IS_KERNEL(addr)    (((addr) & (1ul << 55)) == (1ul << 55))
 /* If true addr is in the user address space */

Reply via email to