]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: introduce xmalloc_aligned_pages
authorArtur Kowalski <arturkow2000@gmail.com>
Thu, 29 Jan 2026 17:42:24 +0000 (18:42 +0100)
committerArtur Kowalski <arturkow2000@gmail.com>
Sun, 15 Feb 2026 14:45:46 +0000 (15:45 +0100)
To be used for block I/O which may require specific buffer alignment.

src/boot/util.c
src/boot/util.h

index 63bf21ae50fe4d68b3a55b81c819c98ccb5c913a..4a4c4e9365012c2b0e9260a5d7fa3a77c9e0af5e 100644 (file)
@@ -517,6 +517,51 @@ void *xmalloc(size_t size) {
         return p;
 }
 
+Pages xmalloc_aligned_pages(
+                EFI_ALLOCATE_TYPE type,
+                EFI_MEMORY_TYPE memory_type,
+                size_t n_pages,
+                size_t alignment,
+                EFI_PHYSICAL_ADDRESS addr) {
+
+        EFI_PHYSICAL_ADDRESS aligned = addr;
+
+        /* Allow to pass block_io->Media->IoAlign to this function directly.
+         * alignment <= 1 means no alignment is required, in that case just
+         * allocate pages directly.
+         */
+        if (alignment <= 1)
+                alignment = EFI_PAGE_SIZE;
+
+        assert(ISPOWEROF2(alignment));
+
+        if (alignment <= EFI_PAGE_SIZE) {
+                assert_se(BS->AllocatePages(type, memory_type, n_pages, &aligned) == EFI_SUCCESS);
+                return (Pages) {
+                        .addr = aligned,
+                        .n_pages = n_pages,
+                };
+        }
+
+        size_t total_pages = n_pages + EFI_SIZE_TO_PAGES(alignment);
+        assert_se(BS->AllocatePages(type, memory_type, total_pages, &addr) == EFI_SUCCESS);
+
+        aligned = ALIGN_TO(addr, alignment);
+        size_t unaligned_pages = EFI_SIZE_TO_PAGES(aligned - addr);
+        if (unaligned_pages > 0)
+                assert_se(BS->FreePages(addr, unaligned_pages) == EFI_SUCCESS);
+
+        addr = aligned + n_pages * EFI_PAGE_SIZE;
+        unaligned_pages = total_pages - n_pages - unaligned_pages;
+        if (unaligned_pages > 0)
+                assert_se(BS->FreePages(addr, unaligned_pages) == EFI_SUCCESS);
+
+        return (Pages) {
+                .addr = aligned,
+                .n_pages = n_pages,
+        };
+}
+
 bool free_and_xstrdup16(char16_t **p, const char16_t *s) {
         char16_t *t;
 
index 59f61c6c39e97251850efeed89e4b784f34646f4..2c8cc36ea580de5a8ec054c1cf8df8ac403b648b 100644 (file)
@@ -96,6 +96,13 @@ static inline Pages xmalloc_pages(
         };
 }
 
+Pages xmalloc_aligned_pages(
+                EFI_ALLOCATE_TYPE type,
+                EFI_MEMORY_TYPE memory_type,
+                size_t n_pages,
+                size_t alignment,
+                EFI_PHYSICAL_ADDRESS addr);
+
 static inline Pages xmalloc_initrd_pages(size_t n_pages) {
         /* The original native x86 boot protocol of the Linux kernel was not 64bit safe, hence we try to
          * allocate memory for the initrds below the 4G boundary on x86, since we don't know early enough