* [PATCH v2 01/20] include: provide linux/errno.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 02/20] include: add linux/refcount.h Ahmad Fatoum
` (19 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We don't have the historic baggage of having to support different errno
definitions depending on architecture. We thus have only
asm-generic/errno.h and include that from errno.h and elsewhere
directly.
Kernel code however includes <linux/errno.h>, so let's provide that file
as well and define there the Linux-specific errno's and include
<asm-generic/errno.h> for all other errnos.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
arch/powerpc/lib/misc.S | 2 +-
arch/powerpc/lib/ppcstring.S | 2 +-
common/optee.c | 2 +-
include/asm-generic/errno.h | 11 ----------
include/bbu.h | 2 +-
include/errno.h | 2 +-
include/linux/err.h | 2 +-
include/linux/errno.h | 36 +++++++++++++++++++++++++++++++++
include/linux/pstore.h | 2 +-
include/mach/at91/iomux.h | 2 +-
include/tee/optee.h | 2 +-
lib/reed_solomon/reed_solomon.c | 2 +-
12 files changed, 46 insertions(+), 21 deletions(-)
create mode 100644 include/linux/errno.h
diff --git a/arch/powerpc/lib/misc.S b/arch/powerpc/lib/misc.S
index c45f02ba3af0..024d26ed58e9 100644
--- a/arch/powerpc/lib/misc.S
+++ b/arch/powerpc/lib/misc.S
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <asm/ppc_asm.tmpl>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
.globl __ashrdi3
__ashrdi3:
diff --git a/arch/powerpc/lib/ppcstring.S b/arch/powerpc/lib/ppcstring.S
index cce85e3252a8..55f96cc9a448 100644
--- a/arch/powerpc/lib/ppcstring.S
+++ b/arch/powerpc/lib/ppcstring.S
@@ -9,7 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/ppc_asm.tmpl>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
.globl strcpy
strcpy:
diff --git a/common/optee.c b/common/optee.c
index b460fbcd0161..32a6c0a15b94 100644
--- a/common/optee.c
+++ b/common/optee.c
@@ -4,7 +4,7 @@
#include <tee/optee.h>
#include <linux/printk.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
int optee_verify_header(struct optee_header *hdr)
{
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index a96f8864dfd4..7629d5c8dd58 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -134,15 +134,4 @@
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
-/* Should never be seen by user programs */
-#define ERESTARTSYS 512
-#define ERESTARTNOINTR 513
-#define ERESTARTNOHAND 514 /* restart if no handler.. */
-#define ENOIOCTLCMD 515 /* No ioctl command */
-#define EPROBE_DEFER 517 /* Driver requests probe retry */
-
-#define ENOTSUPP 524 /* Operation is not supported */
-
-#define _LAST_ERRNO 524
-
#endif
diff --git a/include/bbu.h b/include/bbu.h
index cec7e22d4d90..0a4f324ade5b 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -2,7 +2,7 @@
#ifndef __INCLUDE_BBU_H
#define __INCLUDE_BBU_H
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <linux/list.h>
#include <linux/types.h>
#include <filetype.h>
diff --git a/include/errno.h b/include/errno.h
index 164426596604..6ec7af4d7e9f 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -2,7 +2,7 @@
#ifndef __ERRNO_H
#define __ERRNO_H
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <linux/err.h>
extern int errno;
diff --git a/include/linux/err.h b/include/linux/err.h
index db7ad6cc5bfa..d743b4d0928a 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -5,7 +5,7 @@
#include <linux/compiler.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
/*
* Kernel pointers have redundant information, so we can use a
diff --git a/include/linux/errno.h b/include/linux/errno.h
new file mode 100644
index 000000000000..b3bf44d24936
--- /dev/null
+++ b/include/linux/errno.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ERRNO_H
+#define _LINUX_ERRNO_H
+
+#include <asm-generic/errno.h>
+
+
+/*
+ * These should never be seen by user programs. To return one of ERESTART*
+ * codes, signal_pending() MUST be set. Note that ptrace can observe these
+ * at syscall exit tracing, but they will never be left for the debugged user
+ * process to see.
+ */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514 /* restart if no handler.. */
+#define ENOIOCTLCMD 515 /* No ioctl command */
+#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+#define EPROBE_DEFER 517 /* Driver requests probe retry */
+#define EOPENSTALE 518 /* open found a stale dentry */
+#define ENOPARAM 519 /* Parameter not supported */
+
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE 521 /* Illegal NFS file handle */
+#define ENOTSYNC 522 /* Update synchronization mismatch */
+#define EBADCOOKIE 523 /* Cookie is stale */
+#define ENOTSUPP 524 /* Operation is not supported */
+#define ETOOSMALL 525 /* Buffer or request is too small */
+#define ESERVERFAULT 526 /* An untranslatable error occurred */
+#define EBADTYPE 527 /* Type not supported by server */
+#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
+#define EIOCBQUEUED 529 /* iocb queued, will get completion event */
+#define ERECALLCONFLICT 530 /* conflict with recalled state */
+#define ENOGRACE 531 /* NFS file lock reclaim refused */
+
+#endif
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index f598f31a5438..90e3bd2d4255 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -23,7 +23,7 @@
#include <linux/time.h>
#include <linux/types.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
struct module;
diff --git a/include/mach/at91/iomux.h b/include/mach/at91/iomux.h
index 84b50e05e0dc..f3ac93474222 100644
--- a/include/mach/at91/iomux.h
+++ b/include/mach/at91/iomux.h
@@ -7,7 +7,7 @@
#define __ASM_ARCH_AT91_GPIO_H
#include <io.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <mach/at91/at91_pio.h>
#include <mach/at91/hardware.h>
#include <mach/at91/gpio.h>
diff --git a/include/tee/optee.h b/include/tee/optee.h
index fa124236ba5e..607f5072d385 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -11,7 +11,7 @@
#define _OPTEE_H
#include <types.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#define OPTEE_MAGIC 0x4554504f
#define OPTEE_VERSION 1
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index 51c67c3c8d5d..80c0ec4f7ab9 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -44,7 +44,7 @@
#include <module.h>
#include <linux/string.h>
#include <stdio.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
/* This list holds all currently allocated rs control structures */
static LIST_HEAD (rslist);
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 02/20] include: add linux/refcount.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 01/20] include: provide linux/errno.h Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 03/20] bitops: split off linux/bits.h Ahmad Fatoum
` (18 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
For complex interactions, especially in communication protocols, it can
be beneficial to keep the reference counts used in the Linux drivers as
is to avoid resource leaks or use-after-frees.
Provide a simplified kref and refcount API to facilitate this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/asm-generic/cmpxchg-local.h | 64 +++++++
include/asm-generic/cmpxchg.h | 26 +++
include/linux/atomic.h | 63 +++++++
include/linux/kref.h | 90 +++++++++
include/linux/refcount.h | 271 ++++++++++++++++++++++++++++
lib/Makefile | 1 +
lib/refcount.c | 34 ++++
7 files changed, 549 insertions(+)
create mode 100644 include/asm-generic/cmpxchg-local.h
create mode 100644 include/asm-generic/cmpxchg.h
create mode 100644 include/linux/kref.h
create mode 100644 include/linux/refcount.h
create mode 100644 lib/refcount.c
diff --git a/include/asm-generic/cmpxchg-local.h b/include/asm-generic/cmpxchg-local.h
new file mode 100644
index 000000000000..d93b103d5ca2
--- /dev/null
+++ b/include/asm-generic/cmpxchg-local.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H
+#define __ASM_GENERIC_CMPXCHG_LOCAL_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+extern unsigned long wrong_size_cmpxchg(volatile void *ptr)
+ __noreturn;
+
+/*
+ * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned
+ * long parameter, supporting various types of architectures.
+ */
+static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
+ unsigned long old, unsigned long new, int size)
+{
+ unsigned long prev;
+
+ /*
+ * Sanity checking, compile-time.
+ */
+ if (size == 8 && sizeof(unsigned long) != 8)
+ wrong_size_cmpxchg(ptr);
+
+ switch (size) {
+ case 1: prev = *(u8 *)ptr;
+ if (prev == old)
+ *(u8 *)ptr = (u8)new;
+ break;
+ case 2: prev = *(u16 *)ptr;
+ if (prev == old)
+ *(u16 *)ptr = (u16)new;
+ break;
+ case 4: prev = *(u32 *)ptr;
+ if (prev == old)
+ *(u32 *)ptr = (u32)new;
+ break;
+ case 8: prev = *(u64 *)ptr;
+ if (prev == old)
+ *(u64 *)ptr = (u64)new;
+ break;
+ default:
+ wrong_size_cmpxchg(ptr);
+ }
+ return prev;
+}
+
+/*
+ * Generic version of __cmpxchg64_local. Takes an u64 parameter.
+ */
+static inline u64 __generic_cmpxchg64_local(volatile void *ptr,
+ u64 old, u64 new)
+{
+ u64 prev;
+
+ prev = *(u64 *)ptr;
+ if (prev == old)
+ *(u64 *)ptr = new;
+
+ return prev;
+}
+
+#endif
diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h
new file mode 100644
index 000000000000..b90524135efe
--- /dev/null
+++ b/include/asm-generic/cmpxchg.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Generic non-atomic cmpxchg for porting kernel code.
+ */
+
+#ifndef __ASM_GENERIC_CMPXCHG_H
+#define __ASM_GENERIC_CMPXCHG_H
+
+#ifdef CONFIG_SMP
+#error "Cannot use generic cmpxchg on SMP"
+#endif
+
+#include <asm-generic/cmpxchg-local.h>
+
+#define generic_cmpxchg_local(ptr, o, n) ({ \
+ ((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr)))); \
+})
+
+#define generic_cmpxchg64_local(ptr, o, n) \
+ __generic_cmpxchg64_local((ptr), (o), (n))
+
+#define cmpxchg generic_cmpxchg_local
+#define cmpxchg64 generic_cmpxchg64_local
+
+#endif
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 9304ab4a34ba..c7bdf5857ce8 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -3,5 +3,68 @@
#define LINUX_ATOMIC_H_
#include <asm-generic/atomic.h>
+#include <linux/compiler.h>
+#include <asm-generic/cmpxchg.h>
+
+#define raw_cmpxchg_relaxed cmpxchg
+
+/**
+ * raw_atomic_cmpxchg_relaxed() - atomic compare and exchange with relaxed ordering
+ * @v: pointer to atomic_t
+ * @old: int value to compare with
+ * @new: int value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ *
+ * Safe to use in noinstr code; prefer atomic_cmpxchg_relaxed() elsewhere.
+ *
+ * Return: The original value of @v.
+ */
+static __always_inline int
+raw_atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
+{
+ return raw_cmpxchg_relaxed(&v->counter, old, new);
+}
+
+/**
+ * atomic_try_cmpxchg_relaxed() - atomic compare and exchange with relaxed ordering
+ * @v: pointer to atomic_t
+ * @old: pointer to int value to compare with
+ * @new: int value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, updates @old to the current value of @v.
+ *
+ * Return: @true if the exchange occured, @false otherwise.
+ */
+static __always_inline bool
+atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
+{
+ int r, o = *old;
+ r = raw_atomic_cmpxchg_relaxed(v, o, new);
+ if (unlikely(r != o))
+ *old = r;
+ return likely(r == o);
+}
+
+/**
+ * atomic_fetch_add() - atomic add
+ * @i: int value to add
+ * @v: pointer to atomic_t
+ *
+ * Atomically updates @v to (@v + @i).
+ *
+ * Return: The original value of @v.
+ */
+static __always_inline int
+atomic_fetch_add(int i, atomic_t *v)
+{
+ int old = v->counter;
+ v->counter += i;
+ return old;
+}
+#define atomic_fetch_add_relaxed atomic_fetch_add
+#define atomic_fetch_sub(i, v) atomic_fetch_add(-i, v)
+#define atomic_fetch_sub_release atomic_fetch_sub
#endif
diff --git a/include/linux/kref.h b/include/linux/kref.h
new file mode 100644
index 000000000000..6add3d91da95
--- /dev/null
+++ b/include/linux/kref.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * kref.h - library routines for handling generic reference counted objects
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * based on kobject.h which was:
+ * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (C) 2002-2003 Open Source Development Labs
+ */
+
+#ifndef _KREF_H_
+#define _KREF_H_
+
+#include <linux/refcount.h>
+
+struct kref {
+ refcount_t refcount;
+};
+
+#define KREF_INIT(n) { .refcount = REFCOUNT_INIT(n), }
+
+/**
+ * kref_init - initialize object.
+ * @kref: object in question.
+ */
+static inline void kref_init(struct kref *kref)
+{
+ refcount_set(&kref->refcount, 1);
+}
+
+static inline unsigned int kref_read(const struct kref *kref)
+{
+ return refcount_read(&kref->refcount);
+}
+
+/**
+ * kref_get - increment refcount for object.
+ * @kref: object.
+ */
+static inline void kref_get(struct kref *kref)
+{
+ refcount_inc(&kref->refcount);
+}
+
+/**
+ * kref_put - decrement refcount for object.
+ * @kref: object.
+ * @release: pointer to the function that will clean up the object when the
+ * last reference to the object is released.
+ * This pointer is required, and it is not acceptable to pass kfree
+ * in as this function.
+ *
+ * Decrement the refcount, and if 0, call release().
+ * Return 1 if the object was removed, otherwise return 0. Beware, if this
+ * function returns 0, you still can not count on the kref from remaining in
+ * memory. Only use the return value if you want to see if the kref is now
+ * gone, not present.
+ */
+static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
+{
+ if (refcount_dec_and_test(&kref->refcount)) {
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * kref_get_unless_zero - Increment refcount for object unless it is zero.
+ * @kref: object.
+ *
+ * Return non-zero if the increment succeeded. Otherwise return 0.
+ *
+ * This function is intended to simplify locking around refcounting for
+ * objects that can be looked up from a lookup structure, and which are
+ * removed from that lookup structure in the object destructor.
+ * Operations on such objects require at least a read lock around
+ * lookup + kref_get, and a write lock around kref_put + remove from lookup
+ * structure. Furthermore, RCU implementations become extremely tricky.
+ * With a lookup followed by a kref_get_unless_zero *with return value check*
+ * locking in the kref_put path can be deferred to the actual removal from
+ * the lookup structure and RCU lookups become trivial.
+ */
+static inline int __must_check kref_get_unless_zero(struct kref *kref)
+{
+ return refcount_inc_not_zero(&kref->refcount);
+}
+#endif /* _KREF_H_ */
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
new file mode 100644
index 000000000000..81eed1bbadb3
--- /dev/null
+++ b/include/linux/refcount.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_REFCOUNT_H
+#define _LINUX_REFCOUNT_H
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
+#include <linux/limits.h>
+
+/**
+ * typedef refcount_t - variant of atomic_t specialized for reference counts
+ * @refs: atomic_t counter field
+ *
+ * The counter saturates at REFCOUNT_SATURATED and will not move once
+ * there. This avoids wrapping the counter and causing 'spurious'
+ * use-after-free bugs.
+ */
+typedef struct refcount_struct {
+ atomic_t refs;
+} refcount_t;
+
+#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
+#define REFCOUNT_MAX INT_MAX
+#define REFCOUNT_SATURATED (INT_MIN / 2)
+
+enum refcount_saturation_type {
+ REFCOUNT_ADD_NOT_ZERO_OVF,
+ REFCOUNT_ADD_OVF,
+ REFCOUNT_ADD_UAF,
+ REFCOUNT_SUB_UAF,
+ REFCOUNT_DEC_LEAK,
+};
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t);
+
+/**
+ * refcount_set - set a refcount's value
+ * @r: the refcount
+ * @n: value to which the refcount will be set
+ */
+static inline void refcount_set(refcount_t *r, int n)
+{
+ atomic_set(&r->refs, n);
+}
+
+/**
+ * refcount_read - get a refcount's value
+ * @r: the refcount
+ *
+ * Return: the refcount's value
+ */
+static inline unsigned int refcount_read(const refcount_t *r)
+{
+ return atomic_read(&r->refs);
+}
+
+static inline __must_check bool __refcount_add_not_zero(int i, refcount_t *r, int *oldp)
+{
+ int old = refcount_read(r);
+
+ do {
+ if (!old)
+ break;
+ } while (!atomic_try_cmpxchg_relaxed(&r->refs, &old, old + i));
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(old < 0 || old + i < 0))
+ refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
+
+ return old;
+}
+
+/**
+ * refcount_add_not_zero - add a value to a refcount unless it is 0
+ * @i: the value to add to the refcount
+ * @r: the refcount
+ *
+ * Will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_inc(), or one of its variants, should instead be used to
+ * increment a reference count.
+ *
+ * Return: false if the passed refcount is 0, true otherwise
+ */
+static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
+{
+ return __refcount_add_not_zero(i, r, NULL);
+}
+
+static inline void __refcount_add(int i, refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_add_relaxed(i, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(!old))
+ refcount_warn_saturate(r, REFCOUNT_ADD_UAF);
+ else if (unlikely(old < 0 || old + i < 0))
+ refcount_warn_saturate(r, REFCOUNT_ADD_OVF);
+}
+
+/**
+ * refcount_add - add a value to a refcount
+ * @i: the value to add to the refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_inc(), or one of its variants, should instead be used to
+ * increment a reference count.
+ */
+static inline void refcount_add(int i, refcount_t *r)
+{
+ __refcount_add(i, r, NULL);
+}
+
+static inline __must_check bool __refcount_inc_not_zero(refcount_t *r, int *oldp)
+{
+ return __refcount_add_not_zero(1, r, oldp);
+}
+
+/**
+ * refcount_inc_not_zero - increment a refcount unless it is 0
+ * @r: the refcount to increment
+ *
+ * Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED
+ * and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Return: true if the increment was successful, false otherwise
+ */
+static inline __must_check bool refcount_inc_not_zero(refcount_t *r)
+{
+ return __refcount_inc_not_zero(r, NULL);
+}
+
+static inline void __refcount_inc(refcount_t *r, int *oldp)
+{
+ __refcount_add(1, r, oldp);
+}
+
+/**
+ * refcount_inc - increment a refcount
+ * @r: the refcount to increment
+ *
+ * Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller already has a
+ * reference on the object.
+ *
+ * Will WARN if the refcount is 0, as this represents a possible use-after-free
+ * condition.
+ */
+static inline void refcount_inc(refcount_t *r)
+{
+ __refcount_inc(r, NULL);
+}
+
+static inline __must_check bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_sub_release(i, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (old == i)
+ return true;
+
+ if (unlikely(old < 0 || old - i < 0))
+ refcount_warn_saturate(r, REFCOUNT_SUB_UAF);
+
+ return false;
+}
+
+/**
+ * refcount_sub_and_test - subtract from a refcount and test if it is 0
+ * @i: amount to subtract from the refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_dec_and_test(), but it will WARN, return false and
+ * ultimately leak on underflow and will fail to decrement when saturated
+ * at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides an acquire ordering on success such that free()
+ * must come after.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_dec(), or one of its variants, should instead be used to
+ * decrement a reference count.
+ *
+ * Return: true if the resulting refcount is 0, false otherwise
+ */
+static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
+{
+ return __refcount_sub_and_test(i, r, NULL);
+}
+
+static inline __must_check bool __refcount_dec_and_test(refcount_t *r, int *oldp)
+{
+ return __refcount_sub_and_test(1, r, oldp);
+}
+
+/**
+ * refcount_dec_and_test - decrement a refcount and test if it is 0
+ * @r: the refcount
+ *
+ * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
+ * decrement when saturated at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides an acquire ordering on success such that free()
+ * must come after.
+ *
+ * Return: true if the resulting refcount is 0, false otherwise
+ */
+static inline __must_check bool refcount_dec_and_test(refcount_t *r)
+{
+ return __refcount_dec_and_test(r, NULL);
+}
+
+static inline void __refcount_dec(refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_sub_release(1, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(old <= 1))
+ refcount_warn_saturate(r, REFCOUNT_DEC_LEAK);
+}
+
+/**
+ * refcount_dec - decrement a refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_dec(), it will WARN on underflow and fail to decrement
+ * when saturated at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before.
+ */
+static inline void refcount_dec(refcount_t *r)
+{
+ __refcount_dec(r, NULL);
+}
+
+extern __must_check bool refcount_dec_if_one(refcount_t *r);
+extern __must_check bool refcount_dec_not_one(refcount_t *r);
+
+#endif /* _LINUX_REFCOUNT_H */
diff --git a/lib/Makefile b/lib/Makefile
index 9bb871f94f71..8fd950040381 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_BAREBOX_LOGO) += logo/
obj-y += reed_solomon/
obj-$(CONFIG_RATP) += ratp.o
obj-y += list_sort.o
+obj-y += refcount.o
obj-y += int_sqrt.o
obj-y += parseopt.o
obj-y += clz_ctz.o
diff --git a/lib/refcount.c b/lib/refcount.c
new file mode 100644
index 000000000000..8c6f98b48032
--- /dev/null
+++ b/lib/refcount.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Out-of-line refcount functions.
+ */
+
+#include <linux/refcount.h>
+#include <linux/printk.h>
+
+#define REFCOUNT_WARN(str) WARN_ONCE(1, "refcount_t: " str ".\n")
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t)
+{
+ refcount_set(r, REFCOUNT_SATURATED);
+
+ switch (t) {
+ case REFCOUNT_ADD_NOT_ZERO_OVF:
+ REFCOUNT_WARN("saturated; leaking memory");
+ break;
+ case REFCOUNT_ADD_OVF:
+ REFCOUNT_WARN("saturated; leaking memory");
+ break;
+ case REFCOUNT_ADD_UAF:
+ REFCOUNT_WARN("addition on 0; use-after-free");
+ break;
+ case REFCOUNT_SUB_UAF:
+ REFCOUNT_WARN("underflow; use-after-free");
+ break;
+ case REFCOUNT_DEC_LEAK:
+ REFCOUNT_WARN("decrement hit 0; leaking memory");
+ break;
+ default:
+ REFCOUNT_WARN("unknown saturation event!?");
+ }
+}
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 03/20] bitops: split off linux/bits.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 01/20] include: provide linux/errno.h Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 02/20] include: add linux/refcount.h Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 04/20] include: import <linux/instruction_pointer.h> Ahmad Fatoum
` (17 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The bit definitions are split off in Linux into <linux/bits.h>, which
is included by <linux/bitops.h> and extended with bit operations.
Follow through in barebox to simplify porting kernel code and in future
to speed up the build a bit by avoiding pulling in the whole bitops.h,
when only needing macros like BIT().
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/linux/bitops.h | 21 +--------------------
include/linux/bits.h | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 20 deletions(-)
create mode 100644 include/linux/bits.h
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index b0d6ca6ac87f..7646e1563478 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -5,15 +5,9 @@
#include <linux/types.h>
#include <linux/const.h>
+#include <linux/bits.h>
#ifdef __KERNEL__
-#define BIT(nr) (UL(1) << (nr))
-#define BIT_ULL(nr) (ULL(1) << (nr))
-#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG))
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
-#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
-#define BITS_PER_BYTE 8
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u64))
@@ -22,19 +16,6 @@
#define BYTES_TO_BITS(nb) (((BITS_PER_LONG * (nb)) / sizeof(long)))
#endif
-/*
- * Create a contiguous bitmask starting at bit position @l and ending at
- * position @h. For example
- * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
- */
-#define GENMASK(h, l) \
- (((~UL(0)) - (UL(1) << (l)) + 1) & \
- (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
-
-#define GENMASK_ULL(h, l) \
- (((~ULL(0)) - (ULL(1) << (l)) + 1) & \
- (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
-
#ifndef __ASSEMBLY__
/*
* Include this here because some architectures need generic_ffs/fls in
diff --git a/include/linux/bits.h b/include/linux/bits.h
new file mode 100644
index 000000000000..ea5dfa120102
--- /dev/null
+++ b/include/linux/bits.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_BITS_H
+#define __LINUX_BITS_H
+
+#include <linux/types.h>
+#include <linux/const.h>
+#include <asm/bitsperlong.h>
+
+#define BIT(nr) (UL(1) << (nr))
+#define BIT_ULL(nr) (ULL(1) << (nr))
+#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
+#define BITS_PER_BYTE 8
+
+/*
+ * Create a contiguous bitmask starting at bit position @l and ending at
+ * position @h. For example
+ * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
+ */
+#define GENMASK(h, l) \
+ (((~UL(0)) - (UL(1) << (l)) + 1) & \
+ (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
+
+#define GENMASK_ULL(h, l) \
+ (((~ULL(0)) - (ULL(1) << (l)) + 1) & \
+ (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
+
+#endif /* __LINUX_BITS_H */
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 04/20] include: import <linux/instruction_pointer.h>
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (2 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 03/20] bitops: split off linux/bits.h Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 05/20] asm-generic: split off typeconfused readl and friends Ahmad Fatoum
` (16 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
This header provides definitions for getting the instruction pointer and
the return address in a portable manner, which can be useful for
trace outputs where dump_stack would be overkill.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/linux/instruction_pointer.h | 11 +++++++++++
include/linux/kernel.h | 3 +--
2 files changed, 12 insertions(+), 2 deletions(-)
create mode 100644 include/linux/instruction_pointer.h
diff --git a/include/linux/instruction_pointer.h b/include/linux/instruction_pointer.h
new file mode 100644
index 000000000000..6564127a31ba
--- /dev/null
+++ b/include/linux/instruction_pointer.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_INSTRUCTION_POINTER_H
+#define _LINUX_INSTRUCTION_POINTER_H
+
+#define _RET_IP_ (unsigned long)__builtin_return_address(0)
+
+#ifndef _THIS_IP_
+#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
+#endif
+
+#endif /* _LINUX_INSTRUCTION_POINTER_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 0e4ba243915b..da6121888ebd 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -8,6 +8,7 @@
#include <linux/limits.h>
#include <linux/math64.h>
#include <linux/container_of.h>
+#include <linux/instruction_pointer.h>
#include <linux/minmax.h>
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
@@ -117,8 +118,6 @@ extern long long simple_strtoll(const char *,char **,unsigned int);
} \
)
-#define _RET_IP_ (unsigned long)__builtin_return_address(0)
-
extern const char hex_asc[];
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 05/20] asm-generic: split off typeconfused readl and friends
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (3 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 04/20] include: import <linux/instruction_pointer.h> Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 06/20] asm-generic: migrate relaxed helpers into asm-generic/io.h Ahmad Fatoum
` (15 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The MMIO accessors in barebox like readl have the error prone
peculiarity of accepting integer arguments to pointers automatically,
which makes it easy to confuse address and data.
We will add an alternative less error-prone way for new code, so first
split off the typeconfused code into a separate file.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- fix typo in commit message (Sascha)
---
include/asm-generic/io-typeconfused.h | 75 +++++++++++++++++++++++++++
include/asm-generic/io.h | 57 +-------------------
2 files changed, 76 insertions(+), 56 deletions(-)
create mode 100644 include/asm-generic/io-typeconfused.h
diff --git a/include/asm-generic/io-typeconfused.h b/include/asm-generic/io-typeconfused.h
new file mode 100644
index 000000000000..d25ed7db2473
--- /dev/null
+++ b/include/asm-generic/io-typeconfused.h
@@ -0,0 +1,75 @@
+/* Generic I/O port emulation, based on MN10300 code
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_IO_TYPECONFUSED_H
+#define __ASM_GENERIC_IO_TYPECONFUSED_H
+
+#include <linux/string.h> /* for memset() and memcpy() */
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/*****************************************************************************/
+/*
+ * Unlike the definitions in <asm-generic/io.h>, these macros don't complain
+ * about integer arguments and just silently cast them to pointers. This is
+ * a common cause of bugs, but lots of existing code depends on this, so
+ * this header is provided as a transitory measure.
+ */
+
+#ifndef __raw_readb
+#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
+#endif
+
+#ifndef __raw_readw
+#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+#endif
+
+#ifndef __raw_readl
+#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
+#endif
+
+#ifndef readb
+#define readb __raw_readb
+#endif
+
+#ifndef readw
+#define readw(addr) __le16_to_cpu(__raw_readw(addr))
+#endif
+
+#ifndef readl
+#define readl(addr) __le32_to_cpu(__raw_readl(addr))
+#endif
+
+#ifndef __raw_writeb
+#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
+#endif
+
+#ifndef __raw_writew
+#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
+#endif
+
+#ifndef __raw_writel
+#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
+#endif
+
+#ifndef writeb
+#define writeb __raw_writeb
+#endif
+
+#ifndef writew
+#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
+#endif
+
+#ifndef writel
+#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
+#endif
+
+#endif /* __ASM_GENERIC_IO_TYPECONFUSED_H */
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index ab439026928a..6383d71746f1 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -15,62 +15,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/byteorder.h>
-
-/*****************************************************************************/
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the simple architectures, we just read/write the
- * memory location directly.
- */
-
-#ifndef __raw_readb
-#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
-#endif
-
-#ifndef __raw_readw
-#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
-#endif
-
-#ifndef __raw_readl
-#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
-#endif
-
-#ifndef readb
-#define readb __raw_readb
-#endif
-
-#ifndef readw
-#define readw(addr) __le16_to_cpu(__raw_readw(addr))
-#endif
-
-#ifndef readl
-#define readl(addr) __le32_to_cpu(__raw_readl(addr))
-#endif
-
-#ifndef __raw_writeb
-#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
-#endif
-
-#ifndef __raw_writew
-#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
-#endif
-
-#ifndef __raw_writel
-#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
-#endif
-
-#ifndef writeb
-#define writeb __raw_writeb
-#endif
-
-#ifndef writew
-#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
-#endif
-
-#ifndef writel
-#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
-#endif
+#include <asm-generic/io-typeconfused.h>
#ifdef CONFIG_64BIT
static inline u64 __raw_readq(const volatile void __iomem *addr)
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 06/20] asm-generic: migrate relaxed helpers into asm-generic/io.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (4 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 05/20] asm-generic: split off typeconfused readl and friends Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 07/20] include: add linux/io.h with strict prototypes Ahmad Fatoum
` (14 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In preparation for having <io.h> be the include file for type confused
MMIO accessors and <linux/io.h> for typechecked accessors, let's move out
of <io.h> everything that's not directly related to the type confusion.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/asm-generic/io.h | 34 ++++++++++++++++++++++++++++++++++
include/io.h | 34 ----------------------------------
2 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 6383d71746f1..b118979ed1df 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -792,4 +792,38 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
#include <asm-generic/bitio.h>
+#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
+
+#ifndef readq_relaxed
+#define readq_relaxed(addr) readq(addr)
+#endif
+
+#ifndef readl_relaxed
+#define readl_relaxed(addr) readl(addr)
+#endif
+
+#ifndef readw_relaxed
+#define readw_relaxed(addr) readw(addr)
+#endif
+
+#ifndef readb_relaxed
+#define readb_relaxed(addr) readb(addr)
+#endif
+
+#ifndef writeq_relaxed
+#define writeq_relaxed(val, addr) writeq((val), (addr))
+#endif
+
+#ifndef writel_relaxed
+#define writel_relaxed(val, addr) writel((val), (addr))
+#endif
+
+#ifndef writew_relaxed
+#define writew_relaxed(val, addr) writew((val), (addr))
+#endif
+
+#ifndef writeb_relaxed
+#define writeb_relaxed(val, addr) writeb((val), (addr))
+#endif
+
#endif /* __ASM_GENERIC_IO_H */
diff --git a/include/io.h b/include/io.h
index 6a74246ea777..913002072240 100644
--- a/include/io.h
+++ b/include/io.h
@@ -4,38 +4,4 @@
#include <asm/io.h>
-#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
-
-#ifndef readq_relaxed
-#define readq_relaxed(addr) readq(addr)
-#endif
-
-#ifndef readl_relaxed
-#define readl_relaxed(addr) readl(addr)
-#endif
-
-#ifndef readw_relaxed
-#define readw_relaxed(addr) readw(addr)
-#endif
-
-#ifndef readb_relaxed
-#define readb_relaxed(addr) readb(addr)
-#endif
-
-#ifndef writeq_relaxed
-#define writeq_relaxed(val, addr) writeq((val), (addr))
-#endif
-
-#ifndef writel_relaxed
-#define writel_relaxed(val, addr) writel((val), (addr))
-#endif
-
-#ifndef writew_relaxed
-#define writew_relaxed(val, addr) writew((val), (addr))
-#endif
-
-#ifndef writeb_relaxed
-#define writeb_relaxed(val, addr) writeb((val), (addr))
-#endif
-
#endif /* __IO_H */
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 07/20] include: add linux/io.h with strict prototypes
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (5 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 06/20] asm-generic: migrate relaxed helpers into asm-generic/io.h Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 08/20] include: import Linux word-at-a-time.h Ahmad Fatoum
` (13 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Kernel code uses <linux/io.h> instead of <io.h>, which defines readl and
friends as functions with type checks instead of macros that just cast
everything to pointers. Let's provide <linux/io.h> to ease porting as
well and have it have the same semantics.
Eventually, we should be able to get switch <io.h> to include
<linux/io.h> once all in-tree users are migrated.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/asm-generic/io.h | 217 +++++++++++++++++++++++++++++++++++++--
include/linux/io.h | 9 ++
2 files changed, 218 insertions(+), 8 deletions(-)
create mode 100644 include/linux/io.h
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index b118979ed1df..123ad5488ffc 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -13,23 +13,224 @@
#include <linux/string.h> /* for memset() and memcpy() */
#include <linux/compiler.h>
+#include <linux/instruction_pointer.h>
#include <linux/types.h>
#include <asm/byteorder.h>
+
+#ifndef __LINUX_IO_STRICT_PROTOTYPES__
#include <asm-generic/io-typeconfused.h>
+#endif
+
+#define __io_br() barrier()
+#define __io_ar(v) barrier()
+#define __io_bw() barrier()
+#define __io_pbw() __io_bw()
+#define __io_paw() __io_aw()
+#define __io_aw() do { } while (0)
+#define __io_pbr() __io_br()
+#define __io_par(v) __io_ar(v)
+
+static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_read_mmio(u8 width, const volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+
+/*
+ * __raw_{read,write}{b,w,l,q}() access memory in native endianness.
+ *
+ * On some architectures memory mapped IO needs to be accessed differently.
+ * On the simple architectures, we just read/write the memory location
+ * directly.
+ */
+
+#ifndef __raw_readb
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+ return *(const volatile u8 __force *)addr;
+}
+#endif
+
+#ifndef __raw_readw
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+ return *(const volatile u16 __force *)addr;
+}
+#endif
+
+#ifndef __raw_readl
+#define __raw_readl __raw_readl
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+ return *(const volatile u32 __force *)addr;
+}
+#endif
#ifdef CONFIG_64BIT
+#ifndef __raw_readq
+#define __raw_readq __raw_readq
static inline u64 __raw_readq(const volatile void __iomem *addr)
{
- return *(const volatile u64 __force *) addr;
+ return *(const volatile u64 __force *)addr;
}
-#define readq(addr) __le64_to_cpu(__raw_readq(addr))
-
-static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
-{
- *(volatile u64 __force *) addr = b;
-}
-#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr)
#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef __raw_writeb
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 value, volatile void __iomem *addr)
+{
+ *(volatile u8 __force *)addr = value;
+}
+#endif
+
+#ifndef __raw_writew
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 value, volatile void __iomem *addr)
+{
+ *(volatile u16 __force *)addr = value;
+}
+#endif
+
+#ifndef __raw_writel
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 value, volatile void __iomem *addr)
+{
+ *(volatile u32 __force *)addr = value;
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef __raw_writeq
+#define __raw_writeq __raw_writeq
+static inline void __raw_writeq(u64 value, volatile void __iomem *addr)
+{
+ *(volatile u64 __force *)addr = value;
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+/*
+ * {read,write}{b,w,l,q}() access little endian memory and return result in
+ * native endianness.
+ */
+
+#ifndef readb
+#define readb readb
+static inline u8 readb(const volatile void __iomem *addr)
+{
+ u8 val;
+
+ log_read_mmio(8, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __raw_readb(addr);
+ __io_ar(val);
+ log_post_read_mmio(val, 8, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifndef readw
+#define readw readw
+static inline u16 readw(const volatile void __iomem *addr)
+{
+ u16 val;
+
+ log_read_mmio(16, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le16_to_cpu((__le16 __force)__raw_readw(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 16, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifndef readl
+#define readl readl
+static inline u32 readl(const volatile void __iomem *addr)
+{
+ u32 val;
+
+ log_read_mmio(32, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le32_to_cpu((__le32 __force)__raw_readl(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 32, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef readq
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ u64 val;
+
+ log_read_mmio(64, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le64_to_cpu((__le64 __force)__raw_readq(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef writeb
+#define writeb writeb
+static inline void writeb(u8 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writeb(value, addr);
+ __io_aw();
+ log_post_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifndef writew
+#define writew writew
+static inline void writew(u16 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writew((u16 __force)cpu_to_le16(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifndef writel
+#define writel writel
+static inline void writel(u32 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writel((u32 __force)__cpu_to_le32(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef writeq
+#define writeq writeq
+static inline void writeq(u64 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writeq((u64 __force)__cpu_to_le64(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+#endif /* CONFIG_64BIT */
#ifndef PCI_IOBASE
#define PCI_IOBASE ((void __iomem *)RELOC_HIDE((void *)0, 0))
diff --git a/include/linux/io.h b/include/linux/io.h
new file mode 100644
index 000000000000..9119e4e629d7
--- /dev/null
+++ b/include/linux/io.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_IO_H
+#define _LINUX_IO_H
+
+#define __LINUX_IO_STRICT_PROTOTYPES__
+#include <asm/io.h>
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 08/20] include: import Linux word-at-a-time.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (6 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 07/20] include: add linux/io.h with strict prototypes Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-23 8:16 ` [PATCH] fixup! " Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 09/20] string: implement strscpy Ahmad Fatoum
` (12 subsequent siblings)
20 siblings, 1 reply; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The Linux <linux/word-at-a-time.h> interface is used to optimize
searching for bytes in strings by doing word-size comparisons. This will
be used in the implementation of strscpy in a follow-up commit, so
import the generic version here.
A good overview on the interface is available at LWN[1]. Note that
it discuss Linux v3.5. The asm-generic version imported here works
also on little-endian and not only big-endian[2].
[1]: https://lwn.net/Articles/501492/
[2]: Linux kernel commit a6e2f029ae34 ("Make asm/word-at-a-time.h
available on all architectures").
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
arch/arm/include/asm/word-at-a-time.h | 59 ++++++++
arch/kvx/include/asm/word-at-a-time.h | 2 +
arch/mips/include/asm/word-at-a-time.h | 2 +
arch/openrisc/include/asm/word-at-a-time.h | 2 +
arch/powerpc/include/asm/word-at-a-time.h | 156 +++++++++++++++++++++
arch/riscv/include/asm/word-at-a-time.h | 48 +++++++
arch/sandbox/include/asm/word-at-a-time.h | 2 +
arch/x86/include/asm/word-at-a-time.h | 73 ++++++++++
include/asm-generic/word-at-a-time.h | 121 ++++++++++++++++
include/linux/kernel.h | 8 ++
10 files changed, 473 insertions(+)
create mode 100644 arch/arm/include/asm/word-at-a-time.h
create mode 100644 arch/kvx/include/asm/word-at-a-time.h
create mode 100644 arch/mips/include/asm/word-at-a-time.h
create mode 100644 arch/openrisc/include/asm/word-at-a-time.h
create mode 100644 arch/powerpc/include/asm/word-at-a-time.h
create mode 100644 arch/riscv/include/asm/word-at-a-time.h
create mode 100644 arch/sandbox/include/asm/word-at-a-time.h
create mode 100644 arch/x86/include/asm/word-at-a-time.h
create mode 100644 include/asm-generic/word-at-a-time.h
diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f22198a66be3
--- /dev/null
+++ b/arch/arm/include/asm/word-at-a-time.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ */
+#ifndef __ASM_WORD_AT_A_TIME_H
+#define __ASM_WORD_AT_A_TIME_H
+
+#if !defined(__AARCH64EB__) && !defined(__ARMEB__)
+
+#include <linux/kernel.h>
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
+ const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+#define prep_zero_mask(a, bits, c) (bits)
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ unsigned long ret;
+
+#if __LINUX_ARM_ARCH__ >= 8
+ ret = fls64(mask) >> 3;
+#elif __LINUX_ARM_ARCH__ >= 5
+ /* We have clz available. */
+ ret = fls(mask) >> 3;
+#else
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ ret = (0x0ff0001 + mask) >> 23;
+ /* Fix the 1 for 00 case */
+ ret &= mask;
+#endif
+
+ return ret;
+}
+
+#define zero_bytemask(mask) (mask)
+
+#else /* __AARCH64EB__ || __ARMEB__ */
+#include <asm-generic/word-at-a-time.h>
+#endif
+
+#endif /* __ASM_WORD_AT_A_TIME_H */
diff --git a/arch/kvx/include/asm/word-at-a-time.h b/arch/kvx/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/kvx/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/mips/include/asm/word-at-a-time.h b/arch/mips/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/mips/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/openrisc/include/asm/word-at-a-time.h b/arch/openrisc/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/openrisc/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..1de46fbd2e15
--- /dev/null
+++ b/arch/powerpc/include/asm/word-at-a-time.h
@@ -0,0 +1,156 @@
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+/*
+ * Word-at-a-time interfaces for PowerPC.
+ */
+
+#include <linux/kernel.h>
+
+#ifdef __BIG_ENDIAN__
+
+struct word_at_a_time {
+ const unsigned long high_bits, low_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
+
+/* Bit set in the bytes that have a zero */
+static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
+{
+ unsigned long mask = (val & c->low_bits) + c->low_bits;
+ return ~(mask | rhs);
+}
+
+#define create_zero_mask(mask) (mask)
+
+static inline long find_zero(unsigned long mask)
+{
+ long leading_zero_bits;
+
+ asm (PPC_CNTLZL "%0,%1" : "=r" (leading_zero_bits) : "r" (mask));
+ return leading_zero_bits >> 3;
+}
+
+static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+{
+ unsigned long rhs = val | c->low_bits;
+ *data = rhs;
+ return (val + c->high_bits) & ~rhs;
+}
+
+static inline unsigned long zero_bytemask(unsigned long mask)
+{
+ return ~1ul << __fls(mask);
+}
+
+#else
+
+#ifdef CONFIG_64BIT
+
+/* unused */
+struct word_at_a_time {
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { }
+
+/* This will give us 0xff for a NULL char and 0x00 elsewhere */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long ret;
+ unsigned long zero = 0;
+
+ asm("cmpb %0,%1,%2" : "=r" (ret) : "r" (a), "r" (zero));
+ *bits = ret;
+
+ return ret;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+/* Alan Modra's little-endian strlen tail for 64-bit */
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ unsigned long leading_zero_bits;
+ long trailing_zero_bit_mask;
+
+ asm("addi %1,%2,-1\n\t"
+ "andc %1,%1,%2\n\t"
+ "popcntd %0,%1"
+ : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
+ : "b" (bits));
+
+ return leading_zero_bits;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return mask >> 3;
+}
+
+/* This assumes that we never ask for an all 1s bitmask */
+static inline unsigned long zero_bytemask(unsigned long mask)
+{
+ return (1UL << mask) - 1;
+}
+
+#else /* 32-bit case */
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+/*
+ * This is largely generic for little-endian machines, but the
+ * optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+#endif /* CONFIG_64BIT */
+
+#endif /* __BIG_ENDIAN__ */
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..7c086ac6ecd4
--- /dev/null
+++ b/arch/riscv/include/asm/word-at-a-time.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ *
+ * Derived from arch/x86/include/asm/word-at-a-time.h
+ */
+
+#ifndef _ASM_RISCV_WORD_AT_A_TIME_H
+#define _ASM_RISCV_WORD_AT_A_TIME_H
+
+
+#include <linux/kernel.h>
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+static inline unsigned long has_zero(unsigned long val,
+ unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((val - c->one_bits) & ~val) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long val,
+ unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return fls64(mask) >> 3;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+#endif /* _ASM_RISCV_WORD_AT_A_TIME_H */
diff --git a/arch/sandbox/include/asm/word-at-a-time.h b/arch/sandbox/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/sandbox/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..a7e57b7fd617
--- /dev/null
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+#include <linux/kernel.h>
+
+/*
+ * This is largely generic for little-endian machines, but the
+ * optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+ return mask*0x0001020304050608ul >> 56;
+}
+
+#else /* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
new file mode 100644
index 000000000000..95a1d214108a
--- /dev/null
+++ b/include/asm-generic/word-at-a-time.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+#include <linux/kernel.h>
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+
+struct word_at_a_time {
+ const unsigned long high_bits, low_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
+
+/* Bit set in the bytes that have a zero */
+static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
+{
+ unsigned long mask = (val & c->low_bits) + c->low_bits;
+ return ~(mask | rhs);
+}
+
+#define create_zero_mask(mask) (mask)
+
+static inline long find_zero(unsigned long mask)
+{
+ long byte = 0;
+#ifdef CONFIG_64BIT
+ if (mask >> 32)
+ mask >>= 32;
+ else
+ byte = 4;
+#endif
+ if (mask >> 16)
+ mask >>= 16;
+ else
+ byte += 2;
+ return (mask >> 8) ? byte : byte + 1;
+}
+
+static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+{
+ unsigned long rhs = val | c->low_bits;
+ *data = rhs;
+ return (val + c->high_bits) & ~rhs;
+}
+
+#ifndef zero_bytemask
+#define zero_bytemask(mask) (~1ul << __fls(mask))
+#endif
+
+#else
+
+/*
+ * The optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+ return mask*0x0001020304050608ul >> 56;
+}
+
+#else /* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+#endif /* __BIG_ENDIAN */
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index da6121888ebd..4e50f6075189 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -11,6 +11,14 @@
#include <linux/instruction_pointer.h>
#include <linux/minmax.h>
+/**
+ * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value
+ * @x: value to repeat
+ *
+ * NOTE: @x is not checked for > 0xff; larger values produce odd results.
+ */
+#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
+
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define ALIGN_DOWN(x, a) ALIGN((x) - ((a) - 1), (a))
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH] fixup! include: import Linux word-at-a-time.h
2023-11-22 17:29 ` [PATCH v2 08/20] include: import Linux word-at-a-time.h Ahmad Fatoum
@ 2023-11-23 8:16 ` Ahmad Fatoum
0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-23 8:16 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
word-at-a-time: include linux/bitops for fls definitions
In Linux, <linux/kernel.h> includes <linux/bitops.h>, which eventually
defines fls/fls64/__fls. In barebox this is not the case, so we need to
explicitly include <linux/bitops.h>.
Also PPC_CNTLZL isn't supported in barebox. Fix that too to avoid
compile errors on PowerPC.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/include/asm/word-at-a-time.h | 1 +
arch/powerpc/include/asm/bitops.h | 1 +
arch/powerpc/include/asm/word-at-a-time.h | 8 +++++++-
arch/riscv/include/asm/word-at-a-time.h | 1 +
4 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h
index f22198a66be3..a2b20be13d07 100644
--- a/arch/arm/include/asm/word-at-a-time.h
+++ b/arch/arm/include/asm/word-at-a-time.h
@@ -8,6 +8,7 @@
#if !defined(__AARCH64EB__) && !defined(__ARMEB__)
#include <linux/kernel.h>
+#include <linux/bitops.h>
struct word_at_a_time {
const unsigned long one_bits, high_bits;
diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h
index 543612e6ede3..62b09c7da49c 100644
--- a/arch/powerpc/include/asm/bitops.h
+++ b/arch/powerpc/include/asm/bitops.h
@@ -184,6 +184,7 @@ static inline int ffs(int x)
return __ilog2(x & -x) + 1;
}
+#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/hweight.h>
diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h
index 1de46fbd2e15..029740c6dedf 100644
--- a/arch/powerpc/include/asm/word-at-a-time.h
+++ b/arch/powerpc/include/asm/word-at-a-time.h
@@ -6,6 +6,7 @@
*/
#include <linux/kernel.h>
+#include <linux/bitops.h>
#ifdef __BIG_ENDIAN__
@@ -28,7 +29,12 @@ static inline long find_zero(unsigned long mask)
{
long leading_zero_bits;
- asm (PPC_CNTLZL "%0,%1" : "=r" (leading_zero_bits) : "r" (mask));
+#ifdef __powerpc64__
+ asm ("cntlzd %0,%1" : "=r" (leading_zero_bits) : "r" (mask));
+#else
+ asm ("cntlzw %0,%1" : "=r" (leading_zero_bits) : "r" (mask));
+#endif
+
return leading_zero_bits >> 3;
}
diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h
index 7c086ac6ecd4..74f077d38fe0 100644
--- a/arch/riscv/include/asm/word-at-a-time.h
+++ b/arch/riscv/include/asm/word-at-a-time.h
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
+#include <linux/bitops.h>
struct word_at_a_time {
const unsigned long one_bits, high_bits;
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 09/20] string: implement strscpy
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (7 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 08/20] include: import Linux word-at-a-time.h Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 10/20] of: add CONFIG_OF for Linux compatibility Ahmad Fatoum
` (11 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
strscpy is meant to be a safer alternative to strscpy, which always
terminates the destination string and returns an error code if
truncation happens. To enable porting kernel code using it, import the
definition.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/linux/string.h | 3 ++
lib/string.c | 71 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h
index 75c8cf818b39..32ce56939699 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -46,6 +46,9 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
#ifndef __HAVE_ARCH_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t strscpy(char *, const char *, size_t);
+#endif
#ifndef __HAVE_ARCH_STRCAT
extern char * strcat(char *, const char *);
#endif
diff --git a/lib/string.c b/lib/string.c
index 166ef190d6aa..bf0f0455ab3f 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <string.h>
#include <linux/ctype.h>
+#include <asm/word-at-a-time.h>
#include <malloc.h>
#ifndef __HAVE_ARCH_STRCASECMP
@@ -87,6 +88,76 @@ char * strcpy(char * dest,const char *src)
#endif
EXPORT_SYMBOL(strcpy);
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t strscpy(char *dest, const char *src, size_t count)
+{
+ const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+ size_t max = count;
+ long res = 0;
+
+ if (count == 0 || WARN_ON_ONCE(count > INT_MAX))
+ return -E2BIG;
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ /*
+ * If src is unaligned, don't cross a page boundary,
+ * since we don't know if the next page is mapped.
+ */
+ if ((long)src & (sizeof(long) - 1)) {
+ size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1));
+ if (limit < max)
+ max = limit;
+ }
+#else
+ /* If src or dest is unaligned, don't do word-at-a-time. */
+ if (((long) dest | (long) src) & (sizeof(long) - 1))
+ max = 0;
+#endif
+
+ /*
+ * read_word_at_a_time() below may read uninitialized bytes after the
+ * trailing zero and use them in comparisons. Disable this optimization
+ * under KMSAN to prevent false positive reports.
+ */
+ if (IS_ENABLED(CONFIG_KMSAN))
+ max = 0;
+
+ while (max >= sizeof(unsigned long)) {
+ unsigned long c, data;
+
+ c = read_word_at_a_time(src+res);
+ if (has_zero(c, &data, &constants)) {
+ data = prep_zero_mask(c, data, &constants);
+ data = create_zero_mask(data);
+ *(unsigned long *)(dest+res) = c & zero_bytemask(data);
+ return res + find_zero(data);
+ }
+ *(unsigned long *)(dest+res) = c;
+ res += sizeof(unsigned long);
+ count -= sizeof(unsigned long);
+ max -= sizeof(unsigned long);
+ }
+
+ while (count) {
+ char c;
+
+ c = src[res];
+ dest[res] = c;
+ if (!c)
+ return res;
+ res++;
+ count--;
+ }
+
+ /* Hit buffer length without finding a NUL; force NUL-termination. */
+ if (res)
+ dest[res-1] = '\0';
+
+ return -E2BIG;
+}
+EXPORT_SYMBOL(strscpy);
+#endif
+
/**
* stpcpy - Copy a %NUL terminated string, but return pointer to %NUL
* @dest: Where to copy the string to
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 10/20] of: add CONFIG_OF for Linux compatibility
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (8 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 09/20] string: implement strscpy Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 11/20] include: asm-generic/atomic.h: define atomic_cmpxchg Ahmad Fatoum
` (10 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
barebox has CONFIG_OFTREE and CONFIG_OFDEVICE as separate definitions
for good reason, because configurations parsing device trees, while not
using them are possible. In Linux, there is no such distinction and
CONFIG_OF is used as single option for this. Provide the same option in
barebox as hidden symbol and select it from CONFIG_OFDEVICE to make
porting a tiny bit easier.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
drivers/of/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 4dc40b27f442..816aff0063b0 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -11,8 +11,12 @@ config OFTREE_MEM_GENERIC
config DTC
bool
+config OF
+ bool
+
config OFDEVICE
select OFTREE
+ select OF
select DTC
bool "Enable probing of devices from the devicetree"
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 11/20] include: asm-generic/atomic.h: define atomic_cmpxchg
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (9 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 10/20] of: add CONFIG_OF for Linux compatibility Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 12/20] kbuild: build barebox for -std=gnu11 Ahmad Fatoum
` (9 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We already define a generic cmpxchg implementation, so add one that
operates on atomic_t as well.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/asm-generic/atomic.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 27b0f73b487b..74429e1c373f 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -116,6 +116,8 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
*addr &= ~mask;
}
+#define atomic_cmpxchg(v, o, n) cmpxchg(&((v)->counter), o, n)
+
/* Atomic operations are already serializing on ARM */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 12/20] kbuild: build barebox for -std=gnu11
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (10 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 11/20] include: asm-generic/atomic.h: define atomic_cmpxchg Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 13/20] include: linux/idr.h: implement more Linux API Ahmad Fatoum
` (8 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Linux has been configured with -std=gnu11 since v5.18 to benefit from
being able to declare variables in for loops init statements.
This is handy for barebox as well and should we adopt
__attribute__((cleanup)) to simplify resource management, it will become
required anyway, because define __attribute((cleanup)) variables much
earlier than they are used is needlessly cumbersome.
So let's do the switch.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index dc22ea546428..85bc6515d462 100644
--- a/Makefile
+++ b/Makefile
@@ -387,7 +387,7 @@ HOSTCC = gcc
HOSTCXX = g++
KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
- -O2 -fomit-frame-pointer -std=gnu89
+ -O2 -fomit-frame-pointer -std=gnu11
KBUILD_USERCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
KBUILD_USERLDFLAGS := $(USERLDFLAGS)
@@ -452,7 +452,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__BAREBOX__ $(LINUXINCLUDE) -fno-builti
KBUILD_CFLAGS := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common -fshort-wchar \
-Werror=implicit-function-declaration -Werror=implicit-int \
- -Os -pipe -Wmissing-prototypes -std=gnu89
+ -Os -pipe -Wmissing-prototypes -std=gnu11
KBUILD_AFLAGS := -D__ASSEMBLY__
KBUILD_AFLAGS_KERNEL :=
KBUILD_CFLAGS_KERNEL :=
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 13/20] include: linux/idr.h: implement more Linux API
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (11 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 12/20] kbuild: build barebox for -std=gnu11 Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-30 20:37 ` Sascha Hauer
2023-11-22 17:29 ` [PATCH v2 14/20] test: self: add simple IDR test Ahmad Fatoum
` (7 subsequent siblings)
20 siblings, 1 reply; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Upcoming sync of SCMI with the kernel will start using IDR API, which we
lack in barebox, so let's retrofit it.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- factor out longer IDR functions into separate source file
instead of header
- add IDR Kconfig symbol
- fix implementation of idr_remove, idr_destory, idr_for_each_entry
- keep IDR sorted
---
drivers/firmware/Kconfig | 1 +
drivers/firmware/arm_scmi/driver.c | 4 +-
include/linux/idr.h | 61 ++++++++----------
lib/Kconfig | 3 +
lib/Makefile | 1 +
lib/idr.c | 100 +++++++++++++++++++++++++++++
6 files changed, 133 insertions(+), 37 deletions(-)
create mode 100644 lib/idr.c
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index b4244fb1db6a..ee91b2b7fa6d 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -27,6 +27,7 @@ config ARM_SCMI_PROTOCOL
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || COMPILE_TEST
depends on ARM_SMCCC
+ select IDR
help
ARM System Control and Management Interface (SCMI) protocol is a
set of operating system-independent software interfaces that are
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index dcd15528f394..98f672746527 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -988,7 +988,7 @@ static void scmi_create_protocol_devices(struct device_node *np,
*/
int scmi_protocol_device_request(const struct scmi_device_id *id_table)
{
- int ret = 0;
+ int id, ret = 0;
struct list_head *phead = NULL;
struct scmi_requested_dev *rdev;
struct scmi_info *info;
@@ -1001,7 +1001,7 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
* Search for the matching protocol rdev list and then search
* of any existent equally named device...fails if any duplicate found.
*/
- __idr_for_each_entry(&scmi_requested_devices, idr) {
+ idr_for_each_entry(&scmi_requested_devices, idr, id) {
struct list_head *head = idr->ptr;
if (!phead) {
/* A list found registered in the IDR is never empty */
diff --git a/include/linux/idr.h b/include/linux/idr.h
index 12494b1f01cb..9939085d0e8d 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -24,19 +24,31 @@ struct idr {
#define DEFINE_IDR(name) \
struct idr name = { .list = LIST_HEAD_INIT((name).list) }
-#define __idr_for_each_entry(head, idr) \
- list_for_each_entry((idr), &(head)->list, list)
+/**
+ * idr_for_each_entry() - Iterate over an IDR's elements of a given type.
+ * @_idr: IDR handle.
+ * @_entry: The type * to use as cursor
+ * @_id: Entry ID.
+ *
+ * @_entry and @_id do not need to be initialized before the loop, and
+ * after normal termination @_entry is left with the value NULL. This
+ * is convenient for a "not found" value.
+ */
+#define idr_for_each_entry(_idr, _entry, _id) \
+ for (struct idr *iter = \
+ list_first_entry_or_null(&(_idr)->list, struct idr, list); \
+ (iter && iter != (_idr)) || (_entry = NULL); \
+ iter = list_next_entry(iter, list)) \
+ if ((_entry = iter->ptr, _id = iter->id, true))
-static inline struct idr *__idr_find(struct idr *head, int id)
+struct idr *__idr_find(struct idr *head, int lookup_id);
+
+int idr_for_each(const struct idr *idr,
+ int (*fn)(int id, void *p, void *data), void *data);
+
+static inline int idr_is_empty(const struct idr *idr)
{
- struct idr *idr;
-
- __idr_for_each_entry(head, idr) {
- if (idr->id == id)
- return idr;
- }
-
- return NULL;
+ return list_empty(&idr->list);
}
static inline void *idr_find(struct idr *head, int id)
@@ -46,36 +58,15 @@ static inline void *idr_find(struct idr *head, int id)
return idr ? idr->ptr : NULL;
}
-static inline int idr_alloc_one(struct idr *head, void *ptr, int start)
-{
- struct idr *idr;
-
- if (__idr_find(head, start))
- return -EBUSY;
-
- idr = malloc(sizeof(*idr));
- if (!idr)
- return -ENOMEM;
-
- idr->id = start;
- idr->ptr = ptr;
-
- list_add(&idr->list, &head->list);
-
- return start;
-}
+int idr_alloc_one(struct idr *head, void *ptr, int start);
static inline void idr_init(struct idr *idr)
{
INIT_LIST_HEAD(&idr->list);
}
-static inline void idr_remove(struct idr *head, int id)
-{
- struct idr *idr = __idr_find(head, id);
+void idr_destroy(struct idr *idr);
- list_del(&idr->list);
- free(idr);
-}
+void idr_remove(struct idr *idr, int id);
#endif /* __IDR_H__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index fbc9fff8654c..71715ef6e8ad 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -226,6 +226,9 @@ config GENERIC_ALLOCATOR
help
Support is curently limited to allocaing a complete mmio-sram at once.
+config IDR
+ bool
+
endmenu
source "lib/Kconfig.hardening"
diff --git a/lib/Makefile b/lib/Makefile
index 8fd950040381..38204c8273e5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -28,6 +28,7 @@ obj-y += cmdlinepart.o
obj-y += recursive_action.o
obj-y += make_directory.o
obj-y += math.o
+obj-$(CONFIG_IDR) += idr.o
obj-y += math/
obj-y += uuid.o
obj-$(CONFIG_XXHASH) += xxhash.o
diff --git a/lib/idr.c b/lib/idr.c
new file mode 100644
index 000000000000..10a714ac03f0
--- /dev/null
+++ b/lib/idr.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * 2002-10-18 written by Jim Houston jim.houston@ccur.com
+ * Copyright (C) 2002 by Concurrent Computer Corporation
+ */
+
+#include <errno.h>
+#include <linux/idr.h>
+
+struct idr *__idr_find(struct idr *head, int lookup_id)
+{
+ struct idr *cursor;
+
+ list_for_each_entry(cursor, &head->list, list) {
+ if (cursor->id == lookup_id)
+ return cursor;
+ }
+
+ return NULL;
+}
+
+/**
+ * idr_for_each() - Iterate through all stored pointers.
+ * @idr: IDR handle.
+ * @fn: Function to be called for each pointer.
+ * @data: Data passed to callback function.
+ *
+ * The callback function will be called for each entry in @idr, passing
+ * the ID, the entry and @data.
+ *
+ * If @fn returns anything other than %0, the iteration stops and that
+ * value is returned from this function.
+ */
+int idr_for_each(const struct idr *idr,
+ int (*fn)(int id, void *p, void *data), void *data)
+{
+ const struct idr *pos, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(pos, tmp, &idr->list, list) {
+ ret = fn(pos->id, pos->ptr, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int idr_compare(struct list_head *a, struct list_head *b)
+{
+ int id_a = list_entry(a, struct idr, list)->id;
+ int id_b = list_entry(b, struct idr, list)->id;
+
+ return __compare3(id_a, id_b);
+}
+
+int idr_alloc_one(struct idr *head, void *ptr, int start)
+{
+ struct idr *idr;
+
+ if (__idr_find(head, start))
+ return -EBUSY;
+
+ idr = malloc(sizeof(*idr));
+ if (!idr)
+ return -ENOMEM;
+
+ idr->id = start;
+ idr->ptr = ptr;
+
+ list_add_sort(&idr->list, &head->list, idr_compare);
+
+ return start;
+}
+
+static void __idr_remove(struct idr *idr)
+{
+ list_del(&idr->list);
+ free(idr);
+}
+
+void idr_remove(struct idr *head, int id)
+{
+ struct idr *idr = __idr_find(head, id);
+ if (!idr)
+ return;
+
+ __idr_remove(idr);
+}
+
+void idr_destroy(struct idr *idr)
+{
+ struct idr *pos, *tmp;
+
+ if (!idr)
+ return;
+
+ list_for_each_entry_safe(pos, tmp, &idr->list, list)
+ __idr_remove(pos);
+}
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v2 13/20] include: linux/idr.h: implement more Linux API
2023-11-22 17:29 ` [PATCH v2 13/20] include: linux/idr.h: implement more Linux API Ahmad Fatoum
@ 2023-11-30 20:37 ` Sascha Hauer
0 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2023-11-30 20:37 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Wed, Nov 22, 2023 at 06:29:44PM +0100, Ahmad Fatoum wrote:
> Upcoming sync of SCMI with the kernel will start using IDR API, which we
> lack in barebox, so let's retrofit it.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> v1 -> v2:
> - factor out longer IDR functions into separate source file
> instead of header
> - add IDR Kconfig symbol
> - fix implementation of idr_remove, idr_destory, idr_for_each_entry
> - keep IDR sorted
There's a bug in this patch. With this one applied my Rock3a fails with:
SCMI DRIVER - Requesting SCMI device (clocks) for protocol 0x14
SCMI DRIVER - Requesting SCMI device (regulator) for protocol 0x17
scmi_protocol_device_request: id_table: 0x0000000000000018
scmi_protocol_device_request: name: 0x00786f6265726162
DABT (current EL) exception (ESR 0x96000004) at 0x00786f6265726162
elr: 000000007fd6b8c8 lr : 000000007fd6c3a0
x0 : 00786f6265726162 x1 : 00786f6265726161
x2 : 00786f6265726162 x3 : 00000000ffffffff
x4 : 00000000ffffffff x5 : 0000000000000000
x6 : 00000000ffffffd8 x7 : 000000007fff7a52
x8 : 000000007fff7e48 x9 : 0000000000000020
x10: 0000000000000000 x11: 0000000000000011
x12: 0000000000000010 x13: 000000007fdb34fa
x14: 0000000000000000 x15: 0000000000000007
x16: 000000007fff77b8 x17: 0000000000000007
x18: 000000007fff7e80 x19: 000000007fff7a3e
x20: 00000000ffffffff x21: 00786f6265726162
x22: 000000007fff7e3a x23: 0000000000000000
x24: 000000007fd90dbd x25: 000000007fff7a20
x26: 000000007fff7e80 x27: 000000007fff7e3a
x28: 000000007fff7e80 x29: 000000007fff7910
Call trace:
[<7fd6b8c8>] (strnlen+0x10/0x28) from [<7fd6ca90>] (vsnprintf+0x440/0x71c)
[<7fd6ca90>] (vsnprintf+0x440/0x71c) from [<7fd01198>] (printf+0x6c/0x90)
[<7fd01198>] (printf+0x6c/0x90) from [<7fd5dabc>] (scmi_protocol_device_request+0x154/0x320)
[<7fd5dabc>] (scmi_protocol_device_request+0x154/0x320) from [<7fd5ca38>] (scmi_driver_register+0x34/0x84)
[<7fd5ca38>] (scmi_driver_register+0x34/0x84) from [<7fd59920>] (scmi_drv_register+0x14/0x1c)
[<7fd59920>] (scmi_drv_register+0x14/0x1c) from [<7fd01a2c>] (start_barebox+0x60/0x8c)
[<7fd01a2c>] (start_barebox+0x60/0x8c) from [<7fd8e71c>] (barebox_non_pbl_start+0x11c/0x150)
[<7fd8e71c>] (barebox_non_pbl_start+0x11c/0x150) from [<7fd0000c>] (__bare_init_start+0x0/0x4)
[<7fd0000c>] (__bare_init_start+0x0/0x4) from [<00a01b3c>] (0xa01b3c)
[<00a01b3c>] (0xa01b3c) from [<00a014ec>] (0xa014ec)
The above was printed with these printfs added to scmi_protocol_device_request():
list_for_each_entry(rdev, head, node) {
printf("%s: id_table: 0x%p\n", rdev->id_table);
printf("%s: name: 0x%p\n", rdev->id_table_name);
if (!strcmp(rdev->id_table->name, id_table->name)) {
...
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 14/20] test: self: add simple IDR test
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (12 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 13/20] include: linux/idr.h: implement more Linux API Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 15/20] include: implement dev_warn_once and friends Ahmad Fatoum
` (6 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The barebox implementation for IDR is very rudimentary compared to the
kernel, consisting just of a linked list compared to Linux' radix tree.
Nevertheless, there is potential for wrong implementation, so add a
self test to verify its operation.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- new patch
---
test/self/Kconfig | 5 ++
test/self/Makefile | 1 +
test/self/idr.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 125 insertions(+)
create mode 100644 test/self/idr.c
diff --git a/test/self/Kconfig b/test/self/Kconfig
index 5850dc95973b..ace01accda7e 100644
--- a/test/self/Kconfig
+++ b/test/self/Kconfig
@@ -43,6 +43,7 @@ config SELFTEST_ENABLE_ALL
select SELFTEST_SETJMP if ARCH_HAS_SJLJ
select SELFTEST_REGULATOR if REGULATOR && OFDEVICE
select SELFTEST_TEST_COMMAND if CMD_TEST
+ select SELFTEST_IDR
help
Selects all self-tests compatible with current configuration
@@ -107,4 +108,8 @@ config SELFTEST_TEST_COMMAND
bool "test command selftest"
depends on CMD_TEST
+config SELFTEST_IDR
+ bool "idr selftest"
+ select IDR
+
endif
diff --git a/test/self/Makefile b/test/self/Makefile
index c9ecb459c2d3..51131474f333 100644
--- a/test/self/Makefile
+++ b/test/self/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SELFTEST_STRING) += string.o
obj-$(CONFIG_SELFTEST_SETJMP) += setjmp.o
obj-$(CONFIG_SELFTEST_REGULATOR) += regulator.o test_regulator.dtbo.o
obj-$(CONFIG_SELFTEST_TEST_COMMAND) += test_command.o
+obj-$(CONFIG_SELFTEST_IDR) += idr.o
ifdef REGENERATE_RSATOC
diff --git a/test/self/idr.c b/test/self/idr.c
new file mode 100644
index 000000000000..3d23141e0f03
--- /dev/null
+++ b/test/self/idr.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <printk.h>
+#include <linux/idr.h>
+#include <bselftest.h>
+
+BSELFTEST_GLOBALS();
+
+#define __expect(cond, fmt, ...) ({ \
+ bool __cond = (cond); \
+ total_tests++; \
+ \
+ if (!__cond) { \
+ failed_tests++; \
+ printf("%s failed at %s:%d " fmt "\n", \
+ #cond, __func__, __LINE__, ##__VA_ARGS__); \
+ } \
+ __cond; \
+})
+
+#define expect(ret, ...) __expect((ret), __VA_ARGS__)
+
+static int cmp[3] = { 7, 1, 2};
+static int sorted_cmp[3] = { 1, 2, 7};
+
+static int test_idr_for_each(int id, void *p, void *data)
+{
+ expect(data == &cmp[2]);
+ expect(*(int *)p == id);
+
+ return id == 1 ? 0 : -1;
+}
+
+static int count_idr(int id, void *p, void *data)
+{
+ int *count = data;
+
+ ++*count;
+
+ return 0;
+}
+
+static void test_idr(void)
+{
+ void *ptr;
+ int id, count;
+
+ DEFINE_IDR(idr);
+
+ expect(idr_is_empty(&idr));
+
+ expect(!idr_find(&idr, cmp[0]));
+
+ id = idr_alloc_one(&idr, &cmp[0], cmp[0]);
+ expect(id == cmp[0]);
+
+ expect(!idr_is_empty(&idr));
+
+ ptr = idr_find(&idr, cmp[0]);
+ expect(ptr);
+ expect(ptr == &cmp[0]);
+
+ id = idr_alloc_one(&idr, &cmp[1], cmp[1]);
+ expect(id == cmp[1]);
+
+ id = idr_alloc_one(&idr, &cmp[2], cmp[2]);
+ expect(id == cmp[2]);
+
+ count = 0;
+
+ idr_for_each_entry(&idr, ptr, id) {
+ expect(id == sorted_cmp[count]);
+ expect(*(int *)ptr == sorted_cmp[count]);
+
+ count++;
+
+ }
+
+ expect(count == 3);
+
+ expect(idr_for_each(&idr, test_idr_for_each, &cmp[2]) == -1);
+
+ count = 0;
+ expect(idr_for_each(&idr, count_idr, &count) == 0);
+ expect(count == 3);
+
+ idr_remove(&idr, 1);
+
+ count = 0;
+ expect(idr_for_each(&idr, count_idr, &count) == 0);
+ expect(count == 2);
+
+ idr_remove(&idr, 7);
+
+ count = 0;
+ expect(idr_for_each(&idr, count_idr, &count) == 0);
+ expect(count == 1);
+
+ idr_remove(&idr, 2);
+
+ count = 0;
+ expect(idr_for_each(&idr, count_idr, &count) == 0);
+ expect(count == 0);
+
+ expect(idr_is_empty(&idr));
+
+ idr_alloc_one(&idr, &cmp[0], cmp[0]);
+ idr_alloc_one(&idr, &cmp[1], cmp[1]);
+ idr_alloc_one(&idr, &cmp[2], cmp[2]);
+
+ expect(!idr_is_empty(&idr));
+
+ idr_destroy(&idr);
+
+ expect(idr_is_empty(&idr));
+}
+bselftest(core, test_idr);
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 15/20] include: implement dev_warn_once and friends
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (13 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 14/20] test: self: add simple IDR test Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 16/20] include: add blocking notifier aliases Ahmad Fatoum
` (5 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We already have pr_*_once, so duplicate it for dev_warn and friends as
well.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- squash IDR hunk into previous commit (Sascha)
---
include/linux/printk.h | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index cd4c3cb68edb..0e9604bbe967 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -57,7 +57,15 @@ static inline int pr_print(int level, const char *format, ...)
(level) <= LOGLEVEL ? dev_printf((level), (dev), (format), ##args) : 0; \
})
-
+#define __dev_printf_once(level, dev, format, args...) do { \
+ static bool __print_once; \
+ \
+ if (!__print_once && (level) <= LOGLEVEL) { \
+ __print_once = true; \
+ dev_printf((level), (dev), (format), ##args); \
+ } \
+} while (0)
+
#define dev_emerg(dev, format, arg...) \
__dev_printf(0, (dev) , format , ## arg)
#define dev_alert(dev, format, arg...) \
@@ -77,6 +85,25 @@ static inline int pr_print(int level, const char *format, ...)
#define dev_vdbg(dev, format, arg...) \
__dev_printf(8, (dev) , format , ## arg)
+#define dev_emerg_once(dev, format, arg...) \
+ __dev_printf_once(0, (dev) , format , ## arg)
+#define dev_alert_once(dev, format, arg...) \
+ __dev_printf_once(1, (dev) , format , ## arg)
+#define dev_crit_once(dev, format, arg...) \
+ __dev_printf_once(2, (dev) , format , ## arg)
+#define dev_err_once(dev, format, arg...) \
+ __dev_prin_oncetf(3, (dev) , format , ## arg)
+#define dev_warn_once(dev, format, arg...) \
+ __dev_printf_once(4, (dev) , format , ## arg)
+#define dev_notice_once(dev, format, arg...) \
+ __dev_printf(_once5, (dev) , format , ## arg)
+#define dev_info_once(dev, format, arg...) \
+ __dev_printf_once(6, (dev) , format , ## arg)
+#define dev_dbg_once(dev, format, arg...) \
+ __dev_prin_oncetf(7, (dev) , format , ## arg)
+#define dev_vdbg_once(dev, format, arg...) \
+ __dev_printf_once(8, (dev) , format , ## arg)
+
#if LOGLEVEL >= MSG_ERR
int dev_err_probe(struct device *dev, int err, const char *fmt, ...)
__attribute__ ((format(__printf__, 3, 4)));
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 16/20] include: add blocking notifier aliases
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (14 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 15/20] include: implement dev_warn_once and friends Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 17/20] include: add Linux ktime API Ahmad Fatoum
` (4 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
All notifiers are blocking in barebox, but to avoid needless mechanical
fixups during porting, just provide the stubs in a new
<linux/notifier.h> header. While at it, also provide NOTIFY_DONE and
NOTIFY_OK for use in the notifier callbacks.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- fix typo in commit message (Sascha)
---
include/linux/notifier.h | 16 ++++++++++++++++
include/notifier.h | 3 +++
2 files changed, 19 insertions(+)
create mode 100644 include/linux/notifier.h
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
new file mode 100644
index 000000000000..25f4921a3e80
--- /dev/null
+++ b/include/linux/notifier.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LINUX_NOTIFIER_H
+#define __LINUX_NOTIFIER_H
+
+#include <notifier.h>
+
+#define BLOCKING_NOTIFIER_HEAD NOTIFIER_HEAD
+
+#define blocking_notifier_call_chain notifier_call_chain
+
+#define blocking_notifier_head notifier_head
+
+#define blocking_notifier_chain_register notifier_chain_register
+#define blocking_notifier_chain_unregister notifier_chain_unregister
+
+#endif
diff --git a/include/notifier.h b/include/notifier.h
index 432b66c4ca5a..093fedb0e8e4 100644
--- a/include/notifier.h
+++ b/include/notifier.h
@@ -35,4 +35,7 @@ int clock_notifier_call_chain(void);
.blocks = LIST_HEAD_INIT((name).blocks), \
};
+#define NOTIFY_DONE 0x0000 /* Don't care */
+#define NOTIFY_OK 0x0001 /* Suits me */
+
#endif /* __NOTIFIER_H */
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 17/20] include: add Linux ktime API
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (15 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 16/20] include: add blocking notifier aliases Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 18/20] of: constify string pointed to by struct of_device_id::compatible Ahmad Fatoum
` (3 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With get_time_ns(), we already have a monotonically increasing nanosecond
counter, so let's define ktime_get() as an alias for it and import the
Linux helpers for doing arithmetic with this ktime_t type.
There is a slight mismatch here as get_time_ns() returns a u64, while
ktime_t is signed, but U64_MAX is > 580 years and half of that is still
a fair bit longer than the expected life time of a device idling with
100% CPU in the barebox shell after an aborted boot.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/linux/ktime.h | 212 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
create mode 100644 include/linux/ktime.h
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
new file mode 100644
index 000000000000..ea368b8802e7
--- /dev/null
+++ b/include/linux/ktime.h
@@ -0,0 +1,212 @@
+/*
+ * include/linux/ktime.h
+ *
+ * ktime_t - nanosecond-resolution time format.
+ *
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar
+ *
+ * data type definitions, declarations, prototypes and macros.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * Credits:
+ *
+ * Roman Zippel provided the ideas and primary code snippets of
+ * the ktime_t union and further simplifications of the original
+ * code.
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_KTIME_H
+#define _LINUX_KTIME_H
+
+#include <linux/time.h>
+#include <clock.h>
+#include <linux/bug.h>
+
+#define KTIME_MAX ((s64)~((u64)1 << 63))
+#define KTIME_MIN (-KTIME_MAX - 1)
+#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
+#define KTIME_SEC_MIN (KTIME_MIN / NSEC_PER_SEC)
+
+/* Nanosecond scalar representation for kernel time values */
+typedef s64 ktime_t;
+
+/**
+ * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
+ * @secs: seconds to set
+ * @nsecs: nanoseconds to set
+ *
+ * Return: The ktime_t representation of the value.
+ */
+static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
+{
+ if (unlikely(secs >= KTIME_SEC_MAX))
+ return KTIME_MAX;
+
+ return secs * NSEC_PER_SEC + (s64)nsecs;
+}
+
+/* Subtract two ktime_t variables. rem = lhs -rhs: */
+#define ktime_sub(lhs, rhs) ((lhs) - (rhs))
+
+/* Add two ktime_t variables. res = lhs + rhs: */
+#define ktime_add(lhs, rhs) ((lhs) + (rhs))
+
+/*
+ * Same as ktime_add(), but avoids undefined behaviour on overflow; however,
+ * this means that you must check the result for overflow yourself.
+ */
+#define ktime_add_unsafe(lhs, rhs) ((u64) (lhs) + (rhs))
+
+/*
+ * Add a ktime_t variable and a scalar nanosecond value.
+ * res = kt + nsval:
+ */
+#define ktime_add_ns(kt, nsval) ((kt) + (nsval))
+
+/*
+ * Subtract a scalar nanosecod from a ktime_t variable
+ * res = kt - nsval:
+ */
+#define ktime_sub_ns(kt, nsval) ((kt) - (nsval))
+
+/* Convert ktime_t to nanoseconds */
+static inline s64 ktime_to_ns(const ktime_t kt)
+{
+ return kt;
+}
+
+/**
+ * ktime_compare - Compares two ktime_t variables for less, greater or equal
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: ...
+ * cmp1 < cmp2: return <0
+ * cmp1 == cmp2: return 0
+ * cmp1 > cmp2: return >0
+ */
+static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
+{
+ if (cmp1 < cmp2)
+ return -1;
+ if (cmp1 > cmp2)
+ return 1;
+ return 0;
+}
+
+/**
+ * ktime_after - Compare if a ktime_t value is bigger than another one.
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: true if cmp1 happened after cmp2.
+ */
+static inline bool ktime_after(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return ktime_compare(cmp1, cmp2) > 0;
+}
+
+/**
+ * ktime_before - Compare if a ktime_t value is smaller than another one.
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: true if cmp1 happened before cmp2.
+ */
+static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return ktime_compare(cmp1, cmp2) < 0;
+}
+
+#if BITS_PER_LONG < 64
+extern s64 __ktime_divns(const ktime_t kt, s64 div);
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
+{
+ /*
+ * Negative divisors could cause an inf loop,
+ * so bug out here.
+ */
+ BUG_ON(div < 0);
+ if (__builtin_constant_p(div) && !(div >> 32)) {
+ s64 ns = kt;
+ u64 tmp = ns < 0 ? -ns : ns;
+
+ do_div(tmp, div);
+ return ns < 0 ? -tmp : tmp;
+ } else {
+ return __ktime_divns(kt, div);
+ }
+}
+#else /* BITS_PER_LONG < 64 */
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
+{
+ /*
+ * 32-bit implementation cannot handle negative divisors,
+ * so catch them on 64bit as well.
+ */
+ WARN_ON(div < 0);
+ return kt / div;
+}
+#endif
+
+static inline s64 ktime_to_us(const ktime_t kt)
+{
+ return ktime_divns(kt, NSEC_PER_USEC);
+}
+
+static inline s64 ktime_to_ms(const ktime_t kt)
+{
+ return ktime_divns(kt, NSEC_PER_MSEC);
+}
+
+static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier)
+{
+ return ktime_to_us(ktime_sub(later, earlier));
+}
+
+static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
+{
+ return ktime_to_ms(ktime_sub(later, earlier));
+}
+
+static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec)
+{
+ return ktime_add_ns(kt, usec * NSEC_PER_USEC);
+}
+
+static inline ktime_t ktime_add_ms(const ktime_t kt, const u64 msec)
+{
+ return ktime_add_ns(kt, msec * NSEC_PER_MSEC);
+}
+
+static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec)
+{
+ return ktime_sub_ns(kt, usec * NSEC_PER_USEC);
+}
+
+static inline ktime_t ktime_sub_ms(const ktime_t kt, const u64 msec)
+{
+ return ktime_sub_ns(kt, msec * NSEC_PER_MSEC);
+}
+
+extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);
+
+static inline ktime_t ns_to_ktime(u64 ns)
+{
+ return ns;
+}
+
+static inline ktime_t ms_to_ktime(u64 ms)
+{
+ return ms * NSEC_PER_MSEC;
+}
+
+static inline ktime_t ktime_get(void)
+{
+ return get_time_ns();
+}
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 18/20] of: constify string pointed to by struct of_device_id::compatible
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (16 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 17/20] include: add Linux ktime API Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 19/20] of: define of_devices_ensure_probed_by_compatible Ahmad Fatoum
` (2 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In Linux struct of_device_id::compatible is a character array, but in
barebox, so far it has been a pointer to char *. As most compatible
strings are smaller than 24 bytes, we are likely saving some space by
using a pointer, so we will keep that is, but let's make the member
const to reflect the fact that it points at immutable strings and to
allow easier use without casting.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- new patch (Sascha)
---
include/of.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/of.h b/include/of.h
index 5686709fcf0a..e99b41ef6f14 100644
--- a/include/of.h
+++ b/include/of.h
@@ -40,7 +40,7 @@ struct device_node {
};
struct of_device_id {
- char *compatible;
+ const char *compatible;
const void *data;
};
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 19/20] of: define of_devices_ensure_probed_by_compatible
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (17 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 18/20] of: constify string pointed to by struct of_device_id::compatible Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-22 17:29 ` [PATCH v2 20/20] include: add linux/device.h wrapper around driver.h Ahmad Fatoum
2023-11-23 14:50 ` [PATCH v2 00/20] prepare for porting OP-TEE communication support Sascha Hauer
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We will need to ensure probe of OP-TEE from SCMI code in a follow-up
commit, so add a small helper to facilitate this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- changed prototype to take const char * instead of char * (Sascha)
---
include/of.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/of.h b/include/of.h
index e99b41ef6f14..7d1df462d8cf 100644
--- a/include/of.h
+++ b/include/of.h
@@ -1221,6 +1221,16 @@ int of_device_disable(struct device_node *node);
int of_device_disable_path(const char *path);
int of_device_disable_by_alias(const char *alias);
+static inline int of_devices_ensure_probed_by_compatible(const char *compatible)
+{
+ struct of_device_id match_id[] = {
+ { .compatible = compatible, },
+ { /* sentinel */ },
+ };
+
+ return of_devices_ensure_probed_by_dev_id(match_id);
+}
+
phandle of_get_tree_max_phandle(struct device_node *root);
phandle of_node_create_phandle(struct device_node *node);
int of_set_property_to_child_phandle(struct device_node *node, char *prop_name);
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 20/20] include: add linux/device.h wrapper around driver.h
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (18 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 19/20] of: define of_devices_ensure_probed_by_compatible Ahmad Fatoum
@ 2023-11-22 17:29 ` Ahmad Fatoum
2023-11-23 14:50 ` [PATCH v2 00/20] prepare for porting OP-TEE communication support Sascha Hauer
20 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2023-11-22 17:29 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We don't have device-scoped resource control and in practice memory
allocated in device functions is only freed when barebox terminates, so
let's accept the fact that most code is leaky and implement devm_
as literal leaky abstractions.
While at it provide some macros to translate Linux API into equivalent
barebox API.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
- unchanged
---
include/linux/device.h | 66 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 include/linux/device.h
diff --git a/include/linux/device.h b/include/linux/device.h
new file mode 100644
index 000000000000..0bd61154ac30
--- /dev/null
+++ b/include/linux/device.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LINUX_DRIVER_H_
+#define LINUX_DRIVER_H_
+
+#include <driver.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <mmu.h>
+
+#define device_driver driver
+
+#define __devm_wrapper(fn, dev, ...) ({ BUG_ON(!dev); fn(__VA_ARGS__); })
+
+#define devm_kmalloc(...) __devm_wrapper(kmalloc, __VA_ARGS__)
+#define devm_krealloc(...) __devm_wrapper(krealloc, __VA_ARGS__)
+#define devm_kvasprintf(...) __devm_wrapper(kvasprintf, __VA_ARGS__)
+#define devm_kasprintf(...) __devm_wrapper(kasprintf, __VA_ARGS__)
+#define devm_kzalloc(...) __devm_wrapper(kzalloc, __VA_ARGS__)
+#define devm_kmalloc_array(...) __devm_wrapper(kmalloc_array, __VA_ARGS__)
+#define devm_kcalloc(...) __devm_wrapper(kcalloc, __VA_ARGS__)
+#define devm_krealloc_array(...) __devm_wrapper(krealloc_array, __VA_ARGS__)
+#define devm_kfree(...) __devm_wrapper(kfree, __VA_ARGS__)
+#define devm_kstrdup(...) __devm_wrapper(kstrdup, __VA_ARGS__)
+#define devm_kstrdup_const(...) __devm_wrapper(kstrdup_const, __VA_ARGS__)
+#define devm_kmemdup(...) __devm_wrapper(kmemdup, __VA_ARGS__)
+#define devm_bitmap_zalloc(dev, nbits, gfp) \
+ __devm_wrapper(bitmap_zalloc, dev, nbits)
+
+#define device_register register_device
+#define device_unregister unregister_device
+
+#define driver_register register_driver
+#define driver_unregister unregister_driver
+
+static inline void __iomem *devm_ioremap(struct device *dev,
+ resource_size_t start,
+ resource_size_t size)
+{
+ if (start)
+ remap_range((void *)start, size, MAP_UNCACHED);
+
+ return IOMEM(start);
+}
+
+static inline int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+ int ret;
+
+ bus_for_each_device(bus, dev) {
+ if (start) {
+ if (dev == start)
+ start = NULL;
+ continue;
+ }
+
+ ret = fn(dev, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v2 00/20] prepare for porting OP-TEE communication support
2023-11-22 17:29 [PATCH v2 00/20] prepare for porting OP-TEE communication support Ahmad Fatoum
` (19 preceding siblings ...)
2023-11-22 17:29 ` [PATCH v2 20/20] include: add linux/device.h wrapper around driver.h Ahmad Fatoum
@ 2023-11-23 14:50 ` Sascha Hauer
20 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2023-11-23 14:50 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Wed, Nov 22, 2023 at 06:29:31PM +0100, Ahmad Fatoum wrote:
> So far, barebox support for OP-TEE was restricted to loading it either
> early in PBL or via bootm and to not step over it when allocating
> memory. This was guarded behind CONFIG_HAVE_OPTEE.
>
> To prepare porting the Linux driver behind CONFIG_OPTEE, which
> brings actual bidirectional communication with OP-TEE to barebox,
> let's import some of the headers and APIs used by the v6.6 Linux
> driver.
>
> v1 -> v2:
> See individual change log in every patch.
>
> Ahmad Fatoum (20):
> include: provide linux/errno.h
> include: add linux/refcount.h
> bitops: split off linux/bits.h
> include: import <linux/instruction_pointer.h>
> asm-generic: split off typeconfused readl and friends
> asm-generic: migrate relaxed helpers into asm-generic/io.h
> include: add linux/io.h with strict prototypes
> include: import Linux word-at-a-time.h
> string: implement strscpy
> of: add CONFIG_OF for Linux compatibility
> include: asm-generic/atomic.h: define atomic_cmpxchg
> kbuild: build barebox for -std=gnu11
> include: linux/idr.h: implement more Linux API
> test: self: add simple IDR test
> include: implement dev_warn_once and friends
> include: add blocking notifier aliases
> include: add Linux ktime API
> of: constify string pointed to by struct of_device_id::compatible
> of: define of_devices_ensure_probed_by_compatible
> include: add linux/device.h wrapper around driver.h
Applied, thanks
Sascha
>
> Makefile | 4 +-
> arch/arm/include/asm/word-at-a-time.h | 59 +++++
> arch/kvx/include/asm/word-at-a-time.h | 2 +
> arch/mips/include/asm/word-at-a-time.h | 2 +
> arch/openrisc/include/asm/word-at-a-time.h | 2 +
> arch/powerpc/include/asm/word-at-a-time.h | 156 +++++++++++
> arch/powerpc/lib/misc.S | 2 +-
> arch/powerpc/lib/ppcstring.S | 2 +-
> arch/riscv/include/asm/word-at-a-time.h | 48 ++++
> arch/sandbox/include/asm/word-at-a-time.h | 2 +
> arch/x86/include/asm/word-at-a-time.h | 73 ++++++
> common/optee.c | 2 +-
> drivers/firmware/Kconfig | 1 +
> drivers/firmware/arm_scmi/driver.c | 4 +-
> drivers/of/Kconfig | 4 +
> include/asm-generic/atomic.h | 2 +
> include/asm-generic/cmpxchg-local.h | 64 +++++
> include/asm-generic/cmpxchg.h | 26 ++
> include/asm-generic/errno.h | 11 -
> include/asm-generic/io-typeconfused.h | 75 ++++++
> include/asm-generic/io.h | 284 +++++++++++++++++----
> include/asm-generic/word-at-a-time.h | 121 +++++++++
> include/bbu.h | 2 +-
> include/errno.h | 2 +-
> include/io.h | 34 ---
> include/linux/atomic.h | 63 +++++
> include/linux/bitops.h | 21 +-
> include/linux/bits.h | 30 +++
> include/linux/device.h | 66 +++++
> include/linux/err.h | 2 +-
> include/linux/errno.h | 36 +++
> include/linux/idr.h | 61 ++---
> include/linux/instruction_pointer.h | 11 +
> include/linux/io.h | 9 +
> include/linux/kernel.h | 11 +-
> include/linux/kref.h | 90 +++++++
> include/linux/ktime.h | 212 +++++++++++++++
> include/linux/notifier.h | 16 ++
> include/linux/printk.h | 29 ++-
> include/linux/pstore.h | 2 +-
> include/linux/refcount.h | 271 ++++++++++++++++++++
> include/linux/string.h | 3 +
> include/mach/at91/iomux.h | 2 +-
> include/notifier.h | 3 +
> include/of.h | 12 +-
> include/tee/optee.h | 2 +-
> lib/Kconfig | 3 +
> lib/Makefile | 2 +
> lib/idr.c | 100 ++++++++
> lib/reed_solomon/reed_solomon.c | 2 +-
> lib/refcount.c | 34 +++
> lib/string.c | 71 ++++++
> test/self/Kconfig | 5 +
> test/self/Makefile | 1 +
> test/self/idr.c | 119 +++++++++
> 55 files changed, 2103 insertions(+), 170 deletions(-)
> create mode 100644 arch/arm/include/asm/word-at-a-time.h
> create mode 100644 arch/kvx/include/asm/word-at-a-time.h
> create mode 100644 arch/mips/include/asm/word-at-a-time.h
> create mode 100644 arch/openrisc/include/asm/word-at-a-time.h
> create mode 100644 arch/powerpc/include/asm/word-at-a-time.h
> create mode 100644 arch/riscv/include/asm/word-at-a-time.h
> create mode 100644 arch/sandbox/include/asm/word-at-a-time.h
> create mode 100644 arch/x86/include/asm/word-at-a-time.h
> create mode 100644 include/asm-generic/cmpxchg-local.h
> create mode 100644 include/asm-generic/cmpxchg.h
> create mode 100644 include/asm-generic/io-typeconfused.h
> create mode 100644 include/asm-generic/word-at-a-time.h
> create mode 100644 include/linux/bits.h
> create mode 100644 include/linux/device.h
> create mode 100644 include/linux/errno.h
> create mode 100644 include/linux/instruction_pointer.h
> create mode 100644 include/linux/io.h
> create mode 100644 include/linux/kref.h
> create mode 100644 include/linux/ktime.h
> create mode 100644 include/linux/notifier.h
> create mode 100644 include/linux/refcount.h
> create mode 100644 lib/idr.c
> create mode 100644 lib/refcount.c
> create mode 100644 test/self/idr.c
>
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 24+ messages in thread