[PATCH 1/2] ARM: kuser: move interface documentation out of the source code

Dave Martin dave.martin at linaro.org
Mon Jun 20 07:19:22 EDT 2011


On Sun, Jun 19, 2011 at 12:54:53PM -0400, Nicolas Pitre wrote:
> From: Nicolas Pitre <nicolas.pitre at linaro.org>
> 
> Digging into some assembly file in order to get information about the
> kuser helpers is not that convivial.  Let's move that information to
> a better formatted file in Documentation/arm/ and improve on it a bit.
> 
> Thanks to Dave Martin <dave.martin at linaro.org> for the initial cleanup and
> clarifications.
> 
> Signed-off-by: Nicolas Pitre <nicolas.pitre at linaro.org>

Good to see this, thanks.

Since the technical content is mostly pasted from entry-armv.S, I asssume that
it is still correct.

Acked-by: Dave Martin <dave.martin at linaro.org>

> ---
>  Documentation/arm/kernel_user_helpers.txt |  204 +++++++++++++++++++++++++++++
>  arch/arm/kernel/entry-armv.S              |  152 +---------------------
>  2 files changed, 205 insertions(+), 151 deletions(-)
>  create mode 100644 Documentation/arm/kernel_user_helpers.txt
> 
> diff --git a/Documentation/arm/kernel_user_helpers.txt b/Documentation/arm/kernel_user_helpers.txt
> new file mode 100644
> index 0000000..fa42426
> --- /dev/null
> +++ b/Documentation/arm/kernel_user_helpers.txt
> @@ -0,0 +1,204 @@
> +Kernel-provided User Helpers
> +============================
> +
> +These are segment of kernel provided user code reachable from user space 
> +at a fixed address in kernel memory.  This is used to provide user space 
> +with some operations which require kernel help because of unimplemented 
> +native feature and/or instructions in many ARM CPUs. The idea is for this 
> +code to be executed directly in user mode for best efficiency but which is 
> +too intimate with the kernel counter part to be left to user libraries.  
> +In fact this code might even differ from one CPU to another depending on 
> +the available instruction set, or whether it is a SMP systems. In other 
> +words, the kernel reserves the right to change this code as needed without 
> +warning. Only the entry points and their results as documented here are 
> +guaranteed to be stable.
> +
> +This is different from (but doesn't preclude) a full blown VDSO 
> +implementation, however a VDSO would prevent some assembly tricks with 
> +constants that allows for efficient branching to those code segments. And 
> +since those code segments only use a few cycles before returning to user 
> +code, the overhead of a VDSO indirect far call would add a measurable 
> +overhead to such minimalistic operations.
> +
> +User space is expected to bypass those helpers and implement those things 
> +inline (either in the code emitted directly by the compiler, or part of 
> +the implementation of a library call) when optimizing for a recent enough 
> +processor that has the necessary native support, but only if resulting 
> +binaries are already to be incompatible with earlier ARM processors due to 
> +useage of similar native instructions for other things.  In other words 
> +don't make binaries unable to run on earlier processors just for the sake 
> +of not using these kernel helpers if your compiled code is not going to 
> +use new instructions for other purpose.
> +
> +New helpers may be added over time, so an older kernel may be missing some 
> +helpers present in a newer kernel.  For this reason, programs must check 
> +the value of __kuser_helper_version (see below) before assuming that it is 
> +safe to call any particular helper.  This check should ideally be 
> +performed only once at process startup time, and execution aborted early 
> +if the required helpers are not provided by the kernel version that 
> +process is running on.
> +
> +kuser_helper_version
> +--------------------
> +
> +Location:	0xffff0ffc
> +
> +Reference declaration:
> +
> +  extern int32_t __kuser_helper_version;
> +
> +Definition:
> +
> +  This field contains the number of helpers being implemented by the
> +  running kernel.  User space may read this to determine the availability
> +  of a particular helper.
> +
> +Usage example:
> +
> +#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
> +
> +void check_kuser_version(void)
> +{
> +	if (__kuser_helper_version < 2) {
> +		fprintf(stderr, "can't do atomic operations, kernel too old\n");
> +		abort();
> +	}
> +}
> +
> +Notes:
> +
> +  User space may assume that the value of this field never changes
> +  during the lifetime of any single process.  This means that this
> +  field can be read once during the initialisation of a library or
> +  startup phase of a program.
> +
> +kuser_get_tls
> +-------------
> +
> +Location:	0xffff0fe0
> +
> +Reference prototype:
> +
> +  void * __kuser_get_tls(void);
> +
> +Input:
> +
> +  lr = return address
> +
> +Output:
> +
> +  r0 = TLS value
> +
> +Clobbered registers:
> +
> +  none
> +
> +Definition:
> +
> +  Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
> +
> +Usage example:
> +
> +typedef void * (__kuser_get_tls_t)(void);
> +#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
> +
> +void foo()
> +{
> +	void *tls = __kuser_get_tls();
> +	printf("TLS = %p\n", tls);
> +}
> +
> +Notes:
> +
> +  - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
> +
> +kuser_cmpxchg
> +-------------
> +
> +Location:	0xffff0fc0
> +
> +Reference prototype:
> +
> +  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
> +
> +Input:
> +
> +  r0 = oldval
> +  r1 = newval
> +  r2 = ptr
> +  lr = return address
> +
> +Output:
> +
> +  r0 = success code (zero or non-zero)
> +  C flag = set if r0 == 0, clear if r0 != 0
> +
> +Clobbered registers:
> +
> +  r3, ip, flags
> +
> +Definition:
> +
> +  Atomically store newval in *ptr only if *ptr is equal to oldval.
> +  Return zero if *ptr was changed or non-zero if no exchange happened.
> +  The C flag is also set if *ptr was changed to allow for assembly
> +  optimization in the calling code.
> +
> +Usage example:
> +
> +typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
> +#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
> +
> +int atomic_add(volatile int *ptr, int val)
> +{
> +	int old, new;
> +
> +	do {
> +		old = *ptr;
> +		new = old + val;
> +	} while(__kuser_cmpxchg(old, new, ptr));
> +
> +	return new;
> +}
> +
> +Notes:
> +
> +  - This routine already includes memory barriers as needed.
> +
> +  - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
> +
> +kuser_memory_barrier
> +--------------------
> +
> +Location:	0xffff0fa0
> +
> +Reference prototype:
> +
> +  void __kuser_memory_barrier(void);
> +
> +Input:
> +
> +  lr = return address
> +
> +Output:
> +
> +  none
> +
> +Clobbered registers:
> +
> +  none
> +
> +Definition:
> +
> +  Apply any needed memory barrier to preserve consistency with data modified
> +  manually and __kuser_cmpxchg usage.
> +
> +Usage example:
> +
> +typedef void (__kuser_dmb_t)(void);
> +#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
> +
> +Notes:
> +
> +  - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
> +
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 5d444b5..63f7907 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -754,36 +754,12 @@ ENDPROC(__switch_to)
>  /*
>   * User helpers.
>   *
> - * These are segment of kernel provided user code reachable from user space
> - * at a fixed address in kernel memory.  This is used to provide user space
> - * with some operations which require kernel help because of unimplemented
> - * native feature and/or instructions in many ARM CPUs. The idea is for
> - * this code to be executed directly in user mode for best efficiency but
> - * which is too intimate with the kernel counter part to be left to user
> - * libraries.  In fact this code might even differ from one CPU to another
> - * depending on the available  instruction set and restrictions like on
> - * SMP systems.  In other words, the kernel reserves the right to change
> - * this code as needed without warning. Only the entry points and their
> - * results are guaranteed to be stable.
> - *
>   * Each segment is 32-byte aligned and will be moved to the top of the high
>   * vector page.  New segments (if ever needed) must be added in front of
>   * existing ones.  This mechanism should be used only for things that are
>   * really small and justified, and not be abused freely.
>   *
> - * User space is expected to implement those things inline when optimizing
> - * for a processor that has the necessary native support, but only if such
> - * resulting binaries are already to be incompatible with earlier ARM
> - * processors due to the use of unsupported instructions other than what
> - * is provided here.  In other words don't make binaries unable to run on
> - * earlier processors just for the sake of not using these kernel helpers
> - * if your compiled code is not going to use the new instructions for other
> - * purpose.
> - *
> - * New helpers may be added over time, so an older kernel may be missing
> - * some helpers present in a newer kernel.  For this reason, programs
> - * must check the value of __kernel_helper_version (see below) before
> - * assuming that it is safe to call any particular helper.
> + * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
>   */
>   THUMB(	.arm	)
>  
> @@ -799,93 +775,12 @@ ENDPROC(__switch_to)
>  	.globl	__kuser_helper_start
>  __kuser_helper_start:
>  
> -/*
> - * Reference prototype:
> - *
> - *	void __kernel_memory_barrier(void)
> - *
> - * Input:
> - *
> - *	lr = return address
> - *
> - * Output:
> - *
> - *	none
> - *
> - * Clobbered:
> - *
> - *	none
> - *
> - * Definition and user space usage example:
> - *
> - *	typedef void (__kernel_dmb_t)(void);
> - *	#define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0)
> - *
> - * Apply any needed memory barrier to preserve consistency with data modified
> - * manually and __kuser_cmpxchg usage.
> - *
> - * Do not attempt to call this function unless __kernel_helper_version >= 3.
> - */
> -
>  __kuser_memory_barrier:				@ 0xffff0fa0
>  	smp_dmb	arm
>  	usr_ret	lr
>  
>  	.align	5
>  
> -/*
> - * Reference prototype:
> - *
> - *	int __kernel_cmpxchg(int oldval, int newval, int *ptr)
> - *
> - * Input:
> - *
> - *	r0 = oldval
> - *	r1 = newval
> - *	r2 = ptr
> - *	lr = return address
> - *
> - * Output:
> - *
> - *	r0 = returned value (zero or non-zero)
> - *	C flag = set if r0 == 0, clear if r0 != 0
> - *
> - * Clobbered:
> - *
> - *	r3, ip, flags
> - *
> - * Definition and user space usage example:
> - *
> - *	typedef int (__kernel_cmpxchg_t)(int oldval, int newval,
> - *					 int volatile *ptr);
> - *	#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
> - *
> - * Atomically store newval in *ptr if *ptr is equal to oldval for user space.
> - * Return zero if *ptr was changed or non-zero if no exchange happened.
> - * The C flag is also set if *ptr was changed to allow for assembly
> - * optimization in the calling code.
> - *
> - * Do not attempt to call this function unless __kernel_helper_version >= 2.
> - *
> - * Notes:
> - *
> - *    - This routine already includes memory barriers as needed.
> - *
> - * For example, a user space atomic_add implementation could look like this:
> - *
> - * int atomic_add(int volatile *ptr, int val)
> - * {
> - *	int newval;
> - *	do {
> - *		int oldval = *ptr;
> - *
> - *		newval = oldval + val;
> - *	while(__kernel_cmpxchg(oldval, newval, ptr));
> - *
> - *	return newval;
> - * }
> - */
> -
>  __kuser_cmpxchg:				@ 0xffff0fc0
>  
>  #if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
> @@ -959,33 +854,6 @@ kuser_cmpxchg_fixup:
>  
>  	.align	5
>  
> -/*
> - * Reference prototype:
> - *
> - *	int __kernel_get_tls(void)
> - *
> - * Input:
> - *
> - *	lr = return address
> - *
> - * Output:
> - *
> - *	r0 = TLS value
> - *
> - * Clobbered:
> - *
> - *	none
> - *
> - * Definition and user space usage example:
> - *
> - *	typedef int (__kernel_get_tls_t)(void);
> - *	#define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0)
> - *
> - * Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
> - *
> - * Do not attempt to call this function unless __kernel_helper_version >= 1.
> - */
> -
>  __kuser_get_tls:				@ 0xffff0fe0
>  	ldr	r0, [pc, #(16 - 8)]	@ read TLS, set in kuser_get_tls_init
>  	usr_ret	lr
> @@ -994,24 +862,6 @@ __kuser_get_tls:				@ 0xffff0fe0
>  	.word	0			@ 0xffff0ff0 software TLS value, then
>  	.endr				@ pad up to __kuser_helper_version
>  
> -/*
> - * Reference declaration:
> - *
> - *	extern unsigned int __kernel_helper_version;
> - *
> - * Definition and user space usage example:
> - *
> - *	#define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
> - *
> - * User space may read this to determine the curent number of helpers
> - * available.
> - *
> - * User space may assume that the value of this field never changes
> - * during the lifetime of any single process.  This means that this
> - * field can be read once during the initialisation of a library or
> - * startup phase of a program.
> - */
> -
>  __kuser_helper_version:				@ 0xffff0ffc
>  	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)
>  
> -- 
> 1.7.4
> 



More information about the linux-arm-kernel mailing list