On 6 Aug 2025, at 18:38, Andrew Turner <and...@freebsd.org> wrote: > > 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.
I thought Linux’s ABI was that addresses passed to the kernel must be canonical. Is that false, or is there a reason we’re diverging from that design choice? Jessica > 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 */