On Thu, Jun 16, 2022 at 11:30:49AM +0200, Peter Zijlstra wrote: > On Mon, Jun 13, 2022 at 05:36:43PM +0000, Edgecombe, Rick P wrote: > > On Fri, 2022-06-10 at 17:35 +0300, Kirill A. Shutemov wrote: > > > +#ifdef CONFIG_X86_64 > > > +/* > > > + * Mask out tag bits from the address. > > > + * > > > + * Magic with the 'sign' allows to untag userspace pointer without > > > any branches > > > + * while leaving kernel addresses intact. > > > > Trying to understand the magic part here. I guess how it works is, when > > the high bit is set, it does the opposite of untagging the addresses by > > setting the tag bits instead of clearing them. So: > > The magic is really rather simple to see; there's two observations: > > x ^ y ^ y == x > > That is; xor is it's own inverse. And secondly, xor with 1 is a bit > toggle. > > So if we mask a negative value, we destroy the sign. Therefore, if we > xor with the sign-bit, we have a nop for positive numbers and a toggle > for negatives (effectively making them positive, -1, 2s complement > yada-yada) then we can mask, without fear of destroying the sign, and > then we xor again to undo whatever we did before, effectively restoring > the sign. > > Anyway, concequence of all this is that LAM_U48 won't work correct on > 5-level kernels, because the mask will still destroy kernel pointers. Any objection against this variant (was posted in the thread): #define untagged_addr(mm, addr) ({ \ u64 __addr = (__force u64)(addr); \ s64 sign = (s64)__addr >> 63; \ __addr &= (mm)->context.untag_mask | sign; \ (__force __typeof__(addr))__addr; \ }) ? I find it easier to follow and it is LAM_U48-safe. -- Kirill A. Shutemov