summaryrefslogtreecommitdiffstats
path: root/src/boot/efi
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-01-31 15:39:40 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2023-02-23 09:49:56 +0100
commite71f0f63da87fb8043f665a142261bc393fe0216 (patch)
treeeb86d75eafcfbf55091eb2ae37341af9be58f74c /src/boot/efi
parentefi-string: Add startswith8() (diff)
downloadsystemd-e71f0f63da87fb8043f665a142261bc393fe0216.tar.xz
systemd-e71f0f63da87fb8043f665a142261bc393fe0216.zip
efi-string: Add efi_memchr()
Diffstat (limited to 'src/boot/efi')
-rw-r--r--src/boot/efi/efi-string.c14
-rw-r--r--src/boot/efi/efi-string.h2
-rw-r--r--src/boot/efi/test-efi-string.c13
3 files changed, 29 insertions, 0 deletions
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 911579ed5b..a94e2e4c17 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -878,16 +878,30 @@ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
#if SD_BOOT
/* To provide the actual implementation for these we need to remove the redirection to the builtins. */
+# undef memchr
# undef memcmp
# undef memcpy
# undef memset
#else
/* And for userspace unit testing we need to give them an efi_ prefix. */
+# define memchr efi_memchr
# define memcmp efi_memcmp
# define memcpy efi_memcpy
# define memset efi_memset
#endif
+_used_ void *memchr(const void *p, int c, size_t n) {
+ if (!p || n == 0)
+ return NULL;
+
+ const uint8_t *q = p;
+ for (size_t i = 0; i < n; i++)
+ if (q[i] == (unsigned char) c)
+ return (void *) (q + i);
+
+ return NULL;
+}
+
_used_ int memcmp(const void *p1, const void *p2, size_t n) {
const uint8_t *up1 = p1, *up2 = p2;
int r;
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index 0927bbf82d..410bfd8ef5 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -153,6 +153,7 @@ _gnu_printf_(2, 0) _warn_unused_result_ char16_t *xvasprintf_status(EFI_STATUS s
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
* inline its own implementation and instead issue a library call. */
+# define memchr __builtin_memchr
# define memcmp __builtin_memcmp
# define memcpy __builtin_memcpy
# define memset __builtin_memset
@@ -166,6 +167,7 @@ static inline void *mempcpy(void * restrict dest, const void * restrict src, siz
#else
/* For unit testing. */
+void *efi_memchr(const void *p, int c, size_t n);
int efi_memcmp(const void *p1, const void *p2, size_t n);
void *efi_memcpy(void * restrict dest, const void * restrict src, size_t n);
void *efi_memset(void *p, int c, size_t n);
diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c
index be7f8f9b1c..d214b1536e 100644
--- a/src/boot/efi/test-efi-string.c
+++ b/src/boot/efi/test-efi-string.c
@@ -626,6 +626,19 @@ TEST(xvasprintf_status) {
s = mfree(s);
}
+TEST(efi_memchr) {
+ assert_se(streq8(efi_memchr("abcde", 'c', 5), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'c', 3), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'c', 2), NULL));
+ assert_se(streq8(efi_memchr("abcde", 'c', 7), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'q', 5), NULL));
+ assert_se(streq8(efi_memchr("abcde", 'q', 0), NULL));
+ /* Test that the character is interpreted as unsigned char. */
+ assert_se(streq8(efi_memchr("abcde", 'a', 6), efi_memchr("abcde", 'a' + 0x100, 6)));
+ assert_se(streq8(efi_memchr("abcde", 0, 6), ""));
+ assert_se(efi_memchr(NULL, 0, 0) == NULL);
+}
+
TEST(efi_memcmp) {
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
assert_se(efi_memcmp(NULL, NULL, 1) == 0);