From: Casey Connolly Date: Wed, 1 Apr 2026 14:15:19 +0000 (+0200) Subject: string: add strdup_const and kstrdup_const X-Git-Tag: v2026.07-rc1~34^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=139f5292e7985d0326a1d18eee88720255e423dc;p=thirdparty%2Fu-boot.git string: add strdup_const and kstrdup_const 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 --- diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index d59787948fd..48bd4fa8604 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -9,6 +9,7 @@ #define _ASM_GENERIC_SECTIONS_H_ #include +#include /* 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 */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 62381451617..d4ba4d0088a 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -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); diff --git a/include/linux/string.h b/include/linux/string.h index d943fcce690..a8a6cf4af50 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -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 *); diff --git a/lib/string.c b/lib/string.c index d56f88d4a84..302efe048b0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -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