]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/boot/efi/efi-string.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / boot / efi / efi-string.c
index b9ef1548ca24494fe21ab6b1c460905a60aebc97..dfb2b06a75924609807c16f1c32e39f59259a6d3 100644 (file)
@@ -82,8 +82,7 @@ DEFINE_STRNCASECMP(char16_t, strncasecmp16, true);
 
 #define DEFINE_STRCPY(type, name)                                     \
         type *name(type * restrict dest, const type * restrict src) { \
-                assert(dest);                                         \
-                type *ret = dest;                                     \
+                type *ret = ASSERT_PTR(dest);                         \
                                                                       \
                 if (!src) {                                           \
                         *dest = '\0';                                 \
@@ -193,7 +192,8 @@ static bool efi_fnmatch_internal(const char16_t *p, const char16_t *h, int max_d
                                         p++;
                                         if (*p == '\0')
                                                 return false;
-                                        match |= *p == *h;
+                                        if (*p == *h)
+                                                match = true;
                                         can_range = true;
                                         continue;
                                 }
@@ -239,6 +239,38 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
         return efi_fnmatch_internal(pattern, haystack, 32);
 }
 
+#define DEFINE_PARSE_NUMBER(type, name)                                    \
+        bool name(const type *s, uint64_t *ret_u, const type **ret_tail) { \
+                assert(ret_u);                                             \
+                                                                           \
+                if (!s)                                                    \
+                        return false;                                      \
+                                                                           \
+                /* Need at least one digit. */                             \
+                if (*s < '0' || *s > '9')                                  \
+                        return false;                                      \
+                                                                           \
+                uint64_t u = 0;                                            \
+                while (*s >= '0' && *s <= '9') {                           \
+                        if (__builtin_mul_overflow(u, 10, &u))             \
+                                return false;                              \
+                        if (__builtin_add_overflow(u, *s - '0', &u))       \
+                                return false;                              \
+                        s++;                                               \
+                }                                                          \
+                                                                           \
+                if (!ret_tail && *s != '\0')                               \
+                        return false;                                      \
+                                                                           \
+                *ret_u = u;                                                \
+                if (ret_tail)                                              \
+                        *ret_tail = s;                                     \
+                return true;                                               \
+        }
+
+DEFINE_PARSE_NUMBER(char, parse_number8);
+DEFINE_PARSE_NUMBER(char16_t, parse_number16);
+
 int efi_memcmp(const void *p1, const void *p2, size_t n) {
         const uint8_t *up1 = p1, *up2 = p2;
         int r;
@@ -263,6 +295,16 @@ void *efi_memcpy(void * restrict dest, const void * restrict src, size_t n) {
         if (!dest || !src || n == 0)
                 return dest;
 
+#ifdef SD_BOOT
+        /* The firmware-provided memcpy is likely optimized, so use that. The function is guaranteed to be
+         * available by the UEFI spec. We still make it depend on the boot services pointer being set just in
+         * case the compiler emits a call before it is available. */
+        if (_likely_(BS)) {
+                BS->CopyMem(dest, (void *) src, n);
+                return dest;
+        }
+#endif
+
         uint8_t *d = dest;
         const uint8_t *s = src;
 
@@ -280,6 +322,14 @@ void *efi_memset(void *p, int c, size_t n) {
         if (!p || n == 0)
                 return p;
 
+#ifdef SD_BOOT
+        /* See comment in efi_memcpy. Note that the signature has c and n swapped! */
+        if (_likely_(BS)) {
+                BS->SetMem(p, n, c);
+                return p;
+        }
+#endif
+
         uint8_t *q = p;
         while (n > 0) {
                 *q = c;
@@ -294,9 +344,11 @@ void *efi_memset(void *p, int c, size_t n) {
 #  undef memcmp
 #  undef memcpy
 #  undef memset
-/* Provide the actual implementation for the builtins. To prevent a linker error, we mark memcpy/memset as
- * weak, because gnu-efi is currently providing them. */
-__attribute__((alias("efi_memcmp"))) int memcmp(const void *p1, const void *p2, size_t n);
-__attribute__((weak, alias("efi_memcpy"))) void *memcpy(void * restrict dest, const void * restrict src, size_t n);
-__attribute__((weak, alias("efi_memset"))) void *memset(void *p, int c, size_t n);
+/* Provide the actual implementation for the builtins by providing aliases. These need to be marked as used,
+ * as otherwise the compiler might remove them but still emit calls, which would break when linking.
+ * To prevent a different linker error, we mark memcpy/memset as weak, because gnu-efi is currently
+ * providing them. */
+__attribute__((used, alias("efi_memcmp"))) int memcmp(const void *p1, const void *p2, size_t n);
+__attribute__((used, weak, alias("efi_memcpy"))) void *memcpy(void * restrict dest, const void * restrict src, size_t n);
+__attribute__((used, weak, alias("efi_memset"))) void *memset(void *p, int c, size_t n);
 #endif