]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
string: add strdup_const and kstrdup_const
authorCasey Connolly <casey.connolly@linaro.org>
Wed, 1 Apr 2026 14:15:19 +0000 (16:15 +0200)
committerTom Rini <trini@konsulko.com>
Tue, 21 Apr 2026 17:19:49 +0000 (11:19 -0600)
Extend Linux compat by adding kstrdup_const(), backed by lib/string.c.
This leverages U-Boots .rodata section on ARM64 to avoid pointlessly
duplicating const strings.

This is used by the Linux CCF_FULL port and may be useful elsewhere
in U-Boot.

Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
include/asm-generic/sections.h
include/linux/compat.h
include/linux/string.h
lib/string.c

index d59787948fd1dddd34530b9a5fb6b79a9e0fca38..48bd4fa860434a3c7dce76d708aae80e3e5ccb50 100644 (file)
@@ -9,6 +9,7 @@
 #define _ASM_GENERIC_SECTIONS_H_
 
 #include <linux/types.h>
+#include <stdbool.h>
 
 /* References to section boundaries */
 
@@ -62,6 +63,24 @@ static inline int arch_is_kernel_data(unsigned long addr)
 }
 #endif
 
+/**
+ * is_kernel_rodata - checks if the pointer address is located in the
+ *                    .rodata section
+ *
+ * @addr: address to check
+ *
+ * Returns: true if the address is located in .rodata, false otherwise.
+ */
+static inline bool is_kernel_rodata(unsigned long addr)
+{
+#ifdef CONFIG_ARM64
+       return addr >= (unsigned long)__start_rodata &&
+              addr < (unsigned long)__end_rodata;
+#else
+       return false;
+#endif
+}
+
 /* U-Boot-specific things begin here */
 
 /* Start of U-Boot text region */
index 6238145161759072ad47cb7249a16a286eb794c8..d4ba4d0088a099961ac44947c662ad31237230da 100644 (file)
@@ -67,6 +67,19 @@ static inline void vfree(const void *addr)
        free((void *)addr);
 }
 
+/**
+ * kstrdup_const - conditionally duplicate an existing const string
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Strings allocated by kstrdup_const should be freed by kfree_const and
+ * must not be passed to krealloc().
+ *
+ * Return: source string if it is in .rodata section otherwise
+ * fallback to kstrdup.
+ */
+#define kstrdup_const(s, gfp) strdup_const(s)
+
 struct kmem_cache { int sz; };
 
 struct kmem_cache *get_mem(int element_sz);
index d943fcce690c572c197d5e17309a406be8e30ae8..a8a6cf4af5054f116d79921ba8a487ca159478c0 100644 (file)
@@ -104,6 +104,8 @@ size_t strcspn(const char *s, const char *reject);
 #ifndef __HAVE_ARCH_STRDUP
 extern char * strdup(const char *);
 extern char * strndup(const char *, size_t);
+extern const char *strdup_const(const char *s);
+extern void kfree_const(const void *x);
 #endif
 #ifndef __HAVE_ARCH_STRSWAB
 extern char * strswab(const char *);
index d56f88d4a847a43f7808ca85366faf9db2830bd7..302efe048b07b643d03d7141dc8d27f985afece1 100644 (file)
@@ -379,6 +379,37 @@ char * strndup(const char *s, size_t n)
 
        return new;
 }
+
+/**
+ * strdup_const - conditionally duplicate an existing const string
+ * @s: the string to duplicate
+ *
+ * Note: Strings allocated by kstrdup_const should be freed by kfree_const and
+ * must not be passed to krealloc().
+ *
+ * Return: source string if it is in .rodata section otherwise
+ * fallback to kstrdup.
+ */
+const char *strdup_const(const char *s)
+{
+       if (is_kernel_rodata((unsigned long)s))
+               return s;
+
+       return strdup(s);
+}
+
+/**
+ * kfree_const - conditionally free memory
+ * @x: pointer to the memory
+ *
+ * Function calls kfree only if @x is not in .rodata section.
+ */
+void kfree_const(const void *x)
+{
+       if (!is_kernel_rodata((unsigned long)x))
+               free((void *)x);
+}
+
 #endif
 
 #ifndef __HAVE_ARCH_STRSPN