[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [PATCH 1/2] m68k: Use vDSO for thread pointer access




On 08/01/26 03:18, Stefan wrote:
> Optimize __m68k_read_tp() to read the thread pointer directly from
> the vDSO data page when available, avoiding the get_thread_area
> syscall overhead.
> 
> The kernel maintains the thread pointer in a data page located at
> a fixed offset (PAGE_SIZE) before the vDSO ELF header. This value
> is updated on every context switch and set_thread_area() call.
> 
> The implementation uses lazy initialization: on first call, it
> checks AT_SYSINFO_EHDR from auxv to locate the vDSO. If the vDSO
> is not available (older kernels), it falls back to the syscall.
> 

When was the m68k vDSO support added on Linus tree? I removed some
ancient code that was added based on a out-of-tree patches (commit
112a0ae18b831bf31f44d81b82666980312511d6) and afaik m68k vDSO support
was never added on Linux.

And booting a 6.19.0-rc4+ on qemu I don't see any vDSO page:

$ uname -a
Linux debian-m68k 6.19.0-rc4+ #3 Thu Jan  8 10:55:14 -03 2026 m68k GNU/Linux
$ cat /proc/self/maps
80000000-80007000 r-xp 00000000 08:02 261516     /usr/bin/cat
80009000-8000a000 r--p 00007000 08:02 261516     /usr/bin/cat
8000a000-8000b000 rw-p 00008000 08:02 261516     /usr/bin/cat
8000b000-8002c000 rwxp 00000000 00:00 0          [heap]
c0000000-c0021000 r-xp 00000000 08:02 269185     /usr/lib/m68k-linux-gnu/ld.so.1
c0022000-c0024000 r--p 00022000 08:02 269185     /usr/lib/m68k-linux-gnu/ld.so.1
c0024000-c0025000 rw-p 00024000 08:02 269185     /usr/lib/m68k-linux-gnu/ld.so.1
c0027000-c0029000 rw-p 00000000 00:00 0
c002a000-c01a8000 r-xp 00000000 08:02 269188     /usr/lib/m68k-linux-gnu/libc.so.6
c01a8000-c01a9000 ---p 0017e000 08:02 269188     /usr/lib/m68k-linux-gnu/libc.so.6
c01a9000-c01ae000 r--p 0017f000 08:02 269188     /usr/lib/m68k-linux-gnu/libc.so.6
c01ae000-c01af000 rw-p 00184000 08:02 269188     /usr/lib/m68k-linux-gnu/libc.so.6
c01af000-c01b9000 rw-p 00000000 00:00 0
c01b9000-c03b9000 r--p 00000000 08:02 265523     /usr/lib/locale/locale-archive
c03b9000-c03db000 rw-p 00000000 00:00 0
ef9bf000-ef9e0000 rw-p 00000000 00:00 0          [stack]

Even the qemu user emulation does not provide vDSO support:

$ qemu-m68k ./elf/ld.so --library-path . /tmp/t-m68k
80000000-80001000 r-xp 00000000 103:04 393350                            /tmp/t-m68k
80003000-80004000 r--p 00001000 103:04 393350                            /tmp/t-m68k
80004000-80005000 rw-p 00002000 103:04 393350                            /tmp/t-m68k
c0000000-c0001000 ---p 00000000 00:00 0
c0001000-c0801000 rw-p 00000000 00:00 0                                  [stack]
c0801000-c0802000 r-xp 00000000 00:00 0
c0802000-c0804000 rw-p 00000000 00:00 0
c0804000-c09ae000 r-xp 00000000 103:03 40012242                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/libc.so
c09ae000-c09af000 ---p 001aa000 103:03 40012242                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/libc.so
c09af000-c09b4000 r--p 001a9000 103:03 40012242                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/libc.so
c09b4000-c09b5000 rw-p 001ae000 103:03 40012242                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/libc.so
c09b5000-c09bf000 rw-p 00000000 00:00 0
d0000000-d0023000 r-xp 00000000 103:03 40012241                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/elf/ld.so
d0023000-d0024000 ---p 00000000 00:00 0
d0024000-d0026000 r--p 00022000 103:03 40012241                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/elf/ld.so
d0026000-d0027000 rw-p 00024000 103:03 40012241                          /home/azanella/Projects/glibc/build/m68k-linux-gnu/elf/ld.so
d0027000-d0048000 rw-p 00000000 00:00 0                                  [heap]

> Reviewed-by:
> Tested-by:

I think you missed the entries here.

> 
>       * sysdeps/unix/sysv/linux/m68k/m68k-helpers.c: Include stdint.h
>       and sys/auxv.h.
>       (struct m68k_vdso_data): New struct matching kernel layout.
>       (__m68k_vdso_data): New static variable for cached vDSO pointer.
>       (__m68k_vdso_get): New helper to initialize and return vDSO
>       data pointer.
>       (__m68k_read_tp): Use vDSO fast path when available, fall back
>       to syscall otherwise.

No need to add a CL anymore (it is autogenerated during release).

> ---
>  sysdeps/unix/sysv/linux/m68k/m68k-helpers.c | 77 ++++++++++++++++++++-
>  1 file changed, 76 insertions(+), 1 deletion(-)
> 
> diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
> index 845aae51..1dee48e5 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
> +++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
> @@ -17,9 +17,84 @@
>     <https://www.gnu.org/licenses/>.  */
>  
>  #include <sysdep.h>
> +#include <stdint.h>
> +#include <sys/auxv.h>
>  
> +/*
> + * vDSO data structure - must match the kernel's m68k_vdso_data struct.
> + * The TLS pointer is at offset 0 in the vDSO data page.
> + */
> +struct m68k_vdso_data
> +{
> +  unsigned long tls_ptr;
> +  unsigned long reserved[3];
> +};
> +
> +/*
> + * Pointer to the vDSO data page.
> + * 0 = not yet initialized
> + * -1 = vDSO not available (fallback to syscall)
> + * other = valid vDSO data page address
> + */
> +static volatile struct m68k_vdso_data *__m68k_vdso_data;

This should be done at process initialization, similar how the other vDSO
pointer are done at sysdeps/unix/sysv/linux/dl-vdso-setup.h.  Most likely
it would require a arch-specific hook where to add the logic.

This would allow to optimize the call to avoid the branch to check if the
vDSO is provided (with the fallback being the syscall), similar to how iFUNC 
are internally implemented; and by putting the pointer on the RELRO it would 
not require to add any hardening (as with PTR_MANGLE).

> +
> +/*
> + * Initialize the vDSO pointer on first use.
> + * Returns the pointer to the vDSO data, or NULL if not available.
> + */
> +static inline struct m68k_vdso_data *
> +__m68k_vdso_get (void)
> +{
> +  struct m68k_vdso_data *vdso = (struct m68k_vdso_data *) __m68k_vdso_data;
> +
> +  if (__glibc_unlikely (vdso == NULL))
> +    {
> +      /* Not yet initialized - try to get vDSO base from auxv */
> +      unsigned long sysinfo_ehdr = __getauxval (AT_SYSINFO_EHDR);
> +      if (sysinfo_ehdr != 0)
> +	{
> +	  /*
> +	   * The kernel passes the address of the vDSO ELF header (code page).
> +	   * The vDSO memory layout is:
> +	   *   base + 0x0000: vvar (data page with TLS pointer, clock state)
> +	   *   base + 0x1000: timer page (hardware timer registers)
> +	   *   base + 0x2000: vDSO code (ELF, AT_SYSINFO_EHDR points here)
> +	   * So the data page is 2 * PAGE_SIZE before the code page.
> +	   */
> +	  vdso = (struct m68k_vdso_data *) (sysinfo_ehdr - 2 * 4096);

This is extremely fragile, meaning that if kernel vvar, timer page, or
the vDSO code increase its size it would break. On other architecture
this is transparent and vDSO can be extended any required vvar or code
pages (and it was done for some architecture which extended code required
pages to add new functionalities like the vgetrandom).

This address needs to be provided by a vDSO symbol, complete transparent 
to the userland.

Also, 4096 is wrong here because m68k/coldfire have 8k page sizes.


> +	}
> +      else
> +	{
> +	  /* vDSO not available - mark as unavailable */
> +	  vdso = (struct m68k_vdso_data *) (uintptr_t) -1;
> +	}
> +      __m68k_vdso_data = vdso;
> +    }
> +
> +  /* Return NULL if vDSO is marked as unavailable */
> +  if ((uintptr_t) vdso == (uintptr_t) -1)
> +    return NULL;
> +
> +  return vdso;
> +}
> +
> +/*
> + * Get the thread pointer.
> + *
> + * Fast path: Read directly from the vDSO data page if available.
> + * The kernel updates this on every context switch and set_thread_area() call.
> + *
> + * Slow path: Fall back to the get_thread_area syscall.
> + */
>  void *
>  __m68k_read_tp (void)
>  {
> -  return (void*) INTERNAL_SYSCALL_CALL (get_thread_area);
> +  struct m68k_vdso_data *vdso = __m68k_vdso_get ();
> +
> +  /* Fast path: use vDSO if available */
> +  if (__glibc_likely (vdso != NULL))
> +    return (void *) vdso->tls_ptr;
> +
> +  /* Slow path: syscall fallback */
> +  return (void *) INTERNAL_SYSCALL_CALL (get_thread_area);
>  }


Reply to: