Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package limine for openSUSE:Factory checked 
in at 2026-07-07 21:05:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/limine (Old)
 and      /work/SRC/openSUSE:Factory/.limine.new.1982 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "limine"

Tue Jul  7 21:05:14 2026 rev:45 rq:1364229 version:12.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/limine/limine.changes    2026-06-10 
15:52:27.346984116 +0200
+++ /work/SRC/openSUSE:Factory/.limine.new.1982/limine.changes  2026-07-07 
21:07:55.160083548 +0200
@@ -1,0 +2,9 @@
+Tue Jul  7 09:05:27 UTC 2026 - Marvin Friedrich <[email protected]>
+
+- Update to 12.4.0:
+  * Support booting FreeBSD on BIOS/GPT systems by chainloading the
+    freebsd-boot partition (gptboot), emulating FreeBSD's pmbr.
+  * Add the `firmware_logo` option to restore the OEM firmware boot logo
+    on handoff to the OS via the ACPI BGRT table (UEFI only).
+
+-------------------------------------------------------------------

Old:
----
  limine-12.3.3.tar.gz

New:
----
  limine-12.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ limine.spec ++++++
--- /var/tmp/diff_new_pack.XSS7Zo/_old  2026-07-07 21:07:55.768104562 +0200
+++ /var/tmp/diff_new_pack.XSS7Zo/_new  2026-07-07 21:07:55.776104839 +0200
@@ -15,7 +15,7 @@
 #
 
 Name:           limine
-Version:        12.3.3
+Version:        12.4.0
 Release:        0
 Summary:        Modern, advanced, portable, multiprotocol bootloader and boot 
manager
 License:        BSD-2-Clause

++++++ limine-12.3.3.tar.gz -> limine-12.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/CONFIG.md new/limine-12.4.0/CONFIG.md
--- old/limine-12.3.3/CONFIG.md 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/CONFIG.md 2026-07-01 23:50:19.000000000 +0200
@@ -122,6 +122,11 @@
   when Secure Boot is active, and forced back to `no` if the firmware does
   not expose a TPM 2.0/CC measurement interface. See
   [USAGE.md](USAGE.md#measured-boot).
+* `firmware_logo` - If set to `yes`, restore the OEM firmware boot logo upon
+  handoff to the OS, instead of leaving a blank screen, by clearing the
+  "displayed" status bit in the ACPI BGRT table so the OS redraws the logo
+  itself. The image is re-centred for the active resolution. UEFI only;
+  defaults to `no`.
 
 Limine interface control options:
 
@@ -302,6 +307,12 @@
     identify the drive containing the volume to chainload. Overrides `drive`
     and `mbr_id`, if present, but does *not* override `partition`.
 
+  To boot FreeBSD on a BIOS/GPT disk, point `partition` at the `freebsd-boot`
+  partition. Limine recognises it by its GPT type GUID and emulates FreeBSD's
+  `pmbr`: it loads the whole partition (`gptboot`) and hands off to it, rather
+  than treating it as a conventional boot record (which it is not, as it has no
+  `0xAA55` signature).
+
 ## Paths
 
 A Limine path is used to locate files in the whole system. It is comprised of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/ChangeLog new/limine-12.4.0/ChangeLog
--- old/limine-12.3.3/ChangeLog 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/ChangeLog 2026-07-01 23:50:19.000000000 +0200
@@ -1,3 +1,37 @@
+2026-07-01  Iczelia  <[email protected]>
+
+    *** Release 12.4.0 ***
+
+    Noteworthy changes compared to the previous release, 12.3.3:
+
+    New features:
+        - Support booting FreeBSD on BIOS/GPT systems by chainloading the
+          freebsd-boot partition (gptboot), emulating FreeBSD's pmbr.
+        - Add the `firmware_logo` option to restore the OEM firmware boot logo
+          on handoff to the OS via the ACPI BGRT table (UEFI only).
+
+    Bug fixes:
+        - ASLR has previously used a non-cryptographically secure PRNG,
+          MT19937, which is not ideal for security purposes. New APIs have
+          been added to provide safe hardware-backed randomness where
+          available and ASLR has been switched to use these APIs.
+        - Fix UEFI boot failures in firmware "Fast Boot" mode by connecting
+          all disk controllers before enumerating block devices.
+        - Align concatenated initrd modules to 4 bytes so the Linux kernel
+          finds all concatenated cpio archives.
+        - Fix a memory leak of EDID data when no suitable GOP mode is found.
+        - Fix saving and restoring of variable-range MTRRs on CPUs reporting
+          more than 127 variable ranges.
+        - Consistently reject relocatable ELF kernels that mix lower and
+          higher half PHDRs, regardless of PHDR order.
+        - Harden the Multiboot2, PE, ELF, Linux, chainload, and TFTP loaders
+          against malformed inputs and arithmetic overflows.
+
+    Miscellaneous:
+        - Show the comment for the default entry during timeout.
+        - Replace the general-purpose MT19937 PRNG with PCG, which is smaller,
+          faster, and no longer requires a heap allocation.
+
 2026-06-09  Mintsuki  <[email protected]>
 
     *** Release 12.3.3 ***
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/drivers/disk.s2.c 
new/limine-12.4.0/common/drivers/disk.s2.c
--- old/limine-12.3.3/common/drivers/disk.s2.c  2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/drivers/disk.s2.c  2026-07-01 23:50:19.000000000 
+0200
@@ -721,6 +721,20 @@
 
     unique_sector_pool = ext_mem_alloc(UNIQUE_SECTOR_POOL_SIZE);
 
+    // Fix for ticket #598, in Fast Boot mode the firmware sometimes doesn't 
connect all block
+    // devices until we call ConnectController with the "recursive" flag set.
+    {
+        EFI_HANDLE *all_handles = NULL;
+        UINTN all_handles_count = 0;
+        if (gBS->LocateHandleBuffer(AllHandles, NULL, NULL,
+                                    &all_handles_count, &all_handles) == 
EFI_SUCCESS) {
+            for (UINTN i = 0; i < all_handles_count; i++) {
+                gBS->ConnectController(all_handles[i], NULL, NULL, true);
+            }
+            gBS->FreePool(all_handles);
+        }
+    }
+
     EFI_HANDLE tmp_handles[1];
 
     EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/drivers/gop.c 
new/limine-12.4.0/common/drivers/gop.c
--- old/limine-12.3.3/common/drivers/gop.c      2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/drivers/gop.c      2026-07-01 23:50:19.000000000 
+0200
@@ -357,6 +357,11 @@
             goto retry;
         }
 
+        if (fb->edid != NULL) {
+            pmm_free(fb->edid, sizeof(struct edid_info_struct));
+            fb->edid = NULL;
+        }
+
         continue;
 
 success:;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/acpi.h 
new/limine-12.4.0/common/lib/acpi.h
--- old/limine-12.3.3/common/lib/acpi.h 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/acpi.h 2026-07-01 23:50:19.000000000 +0200
@@ -61,7 +61,7 @@
     /// Minor version of SMBIOS.
     uint8_t minor_version;
     /// Size of the largest SMBIOS structure, in bytes, and encompasses the
-    /// structure’s formatted area and text strings
+    /// structure's formatted area and text strings
     uint16_t max_structure_size;
     uint8_t entry_point_revision;
     char formatted_area[5];
@@ -199,6 +199,16 @@
 #define MADT_CORE_PIC_ENABLED        ((uint32_t)1 << 0)
 #define MADT_CORE_PIC_ONLINE_CAPABLE ((uint32_t)1 << 1)
 
+struct acpi_bgrt {
+    struct sdt header;
+    uint16_t version;
+    uint8_t status;
+    uint8_t image_type;
+    uint64_t image_address;
+    uint32_t image_offset_x;
+    uint32_t image_offset_y;
+} __attribute__((packed));
+
 uint8_t acpi_checksum(void *ptr, size_t size);
 void   *acpi_get_rsdp(void);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/bgrt.c 
new/limine-12.4.0/common/lib/bgrt.c
--- old/limine-12.3.3/common/lib/bgrt.c 1970-01-01 01:00:00.000000000 +0100
+++ new/limine-12.4.0/common/lib/bgrt.c 2026-07-01 23:50:19.000000000 +0200
@@ -0,0 +1,83 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/bgrt.h>
+#include <lib/acpi.h>
+#include <lib/config.h>
+#include <lib/libc.h>
+#include <lib/misc.h>
+
+#if defined (UEFI)
+
+void bgrt_restore(uint64_t fb_width, uint64_t fb_height) {
+    if (!firmware_logo) {
+        return;
+    }
+
+    struct acpi_bgrt *bgrt = acpi_get_table("BGRT", 0);
+    if (bgrt == NULL) {
+        return;
+    }
+
+    if (bgrt->header.length < sizeof(struct acpi_bgrt)) {
+        return;
+    }
+
+    if (bgrt->version != 1) {
+        return;
+    }
+
+    if (bgrt->image_address > UINTPTR_MAX) {
+        return;
+    }
+
+    bgrt->status &= ~1;
+
+    uint8_t *bmp = (uint8_t *)(uintptr_t)bgrt->image_address;
+    if (bmp != NULL && bmp[0] == 'B' && bmp[1] == 'M') {
+        // Firmware BMP size field is unreliable, bounds check is not possible.
+        // The scope is limited to 4 bytes; we choose to trust the firmware 
here.
+        uint32_t dib_header_size;
+        memcpy(&dib_header_size, &bmp[14], sizeof(dib_header_size));
+
+        uint32_t bmp_width = 0;
+        uint32_t bmp_height = 0;
+
+        if (dib_header_size >= 40) {
+            int32_t bmp_height_raw;
+            memcpy(&bmp_width, &bmp[18], sizeof(bmp_width));
+            memcpy(&bmp_height_raw, &bmp[22], sizeof(bmp_height_raw));
+
+            bmp_height = (uint32_t)(bmp_height_raw < 0 ? -bmp_height_raw : 
bmp_height_raw);
+        } else if (dib_header_size == 12) {
+            uint16_t bmp_width_raw;
+            uint16_t bmp_height_raw;
+            memcpy(&bmp_width_raw, &bmp[18], sizeof(bmp_width_raw));
+            memcpy(&bmp_height_raw, &bmp[20], sizeof(bmp_height_raw));
+
+            bmp_width = bmp_width_raw;
+            bmp_height = bmp_height_raw;
+        }
+
+        if (bmp_width > 0 && bmp_height > 0) {
+            if (fb_width >= bmp_width) {
+                bgrt->image_offset_x = (fb_width - bmp_width) / 2;
+            }
+
+            if (fb_height >= bmp_height) {
+                bgrt->image_offset_y = (fb_height - bmp_height) / 2;
+            }
+        }
+    }
+
+    bgrt->header.checksum = 0;
+    bgrt->header.checksum = 256 - acpi_checksum(bgrt, bgrt->header.length);
+}
+
+#else
+
+void bgrt_restore(uint64_t fb_width, uint64_t fb_height) {
+    (void)fb_width;
+    (void)fb_height;
+}
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/bgrt.h 
new/limine-12.4.0/common/lib/bgrt.h
--- old/limine-12.3.3/common/lib/bgrt.h 1970-01-01 01:00:00.000000000 +0100
+++ new/limine-12.4.0/common/lib/bgrt.h 2026-07-01 23:50:19.000000000 +0200
@@ -0,0 +1,7 @@
+#ifndef LIB__BGRT_H__
+#define LIB__BGRT_H__
+#include <stdint.h>
+
+void bgrt_restore(uint64_t fb_width, uint64_t fb_height);
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/elf.c 
new/limine-12.4.0/common/lib/elf.c
--- old/limine-12.3.3/common/lib/elf.c  2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/elf.c  2026-07-01 23:50:19.000000000 +0200
@@ -603,7 +603,7 @@
                     if (s->st_name >= strtab_size) {
                         panic(true, "elf: Symbol name offset out of bounds");
                     }
-                    panic(true, "elf: Unresolved symbol \"%s\"", elf + 
strtab_offset + s->st_name);
+                    panic(true, "elf: Unresolved symbol \"%S\"", elf + 
strtab_offset + s->st_name, (size_t)(strtab_size - s->st_name));
                 }
                 *ptr = slide + s->st_value
 #if defined (__aarch64__)
@@ -648,7 +648,7 @@
                     if (s->st_name >= strtab_size) {
                         panic(true, "elf: Symbol name offset out of bounds");
                     }
-                    panic(true, "elf: Unresolved symbol \"%s\"", elf + 
strtab_offset + s->st_name);
+                    panic(true, "elf: Unresolved symbol \"%S\"", elf + 
strtab_offset + s->st_name, (size_t)(strtab_size - s->st_name));
                 }
                 *ptr = slide + s->st_value + relocation->r_addend;
                 break;
@@ -884,6 +884,7 @@
     uint64_t image_size = 0;
 
     bool lower_to_higher = false;
+    bool higher_half = false;
 
     uint64_t min_vaddr = (uint64_t)-1;
     uint64_t max_vaddr = 0;
@@ -898,11 +899,15 @@
             if (!is_reloc || !*is_reloc) {
                 panic(true, "elf: Lower half PHDRs are not allowed");
             }
+            if (higher_half) {
+                panic(true, "elf: Mix of lower and higher half PHDRs in 
relocatable kernel");
+            }
             lower_to_higher = true;
         } else {
             if (lower_to_higher) {
                 panic(true, "elf: Mix of lower and higher half PHDRs in 
relocatable kernel");
             }
+            higher_half = true;
         }
 
         uint64_t phdr_end = CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz,
@@ -983,7 +988,7 @@
 
 again:
     if (is_reloc && *is_reloc && kaslr) {
-        slide = (rand32() & ~(max_align - 1)) + (lower_to_higher ? 
FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr : 0);
+        slide = (safe_rand32() & ~(max_align - 1)) + (lower_to_higher ? 
FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr : 0);
 
         if (*virtual_base + slide + image_size < 0xffffffff80000000 /* this 
comparison relies on overflow */) {
             if (++try_count == max_simulated_tries) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/fb.c 
new/limine-12.4.0/common/lib/fb.c
--- old/limine-12.3.3/common/lib/fb.c   2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/fb.c   2026-07-01 23:50:19.000000000 +0200
@@ -9,6 +9,7 @@
 #include <mm/mtrr.h>
 #include <mm/efi_pt.h>
 #include <sys/cpu.h>
+#include <lib/bgrt.h>
 
 struct fb_info *fb_fbs;
 size_t fb_fbs_count = 0;
@@ -78,6 +79,12 @@
 #else
     (void)want_wc;
 #endif
+
+#if defined (UEFI)
+    if (!preserve_screen && *_fbs_count > 0) {
+        bgrt_restore((*ret)[0].framebuffer_width, 
(*ret)[0].framebuffer_height);
+    }
+#endif
 }
 
 void fb_clear(struct fb_info *fb) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/misc.h 
new/limine-12.4.0/common/lib/misc.h
--- old/limine-12.3.3/common/lib/misc.h 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/misc.h 2026-07-01 23:50:19.000000000 +0200
@@ -38,7 +38,7 @@
 extern bool stage3_loaded;
 #endif
 
-extern bool quiet, serial, editor_enabled, help_hidden, hash_mismatch_panic, 
secure_boot_active, measured_boot;
+extern bool quiet, serial, editor_enabled, help_hidden, hash_mismatch_panic, 
secure_boot_active, measured_boot, firmware_logo;
 
 extern uint64_t usec_at_bootloader_entry;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/misc.s2.c 
new/limine-12.4.0/common/lib/misc.s2.c
--- old/limine-12.3.3/common/lib/misc.s2.c      2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/lib/misc.s2.c      2026-07-01 23:50:19.000000000 
+0200
@@ -8,6 +8,7 @@
 bool serial = false;
 bool hash_mismatch_panic = false;
 bool measured_boot = false;
+bool firmware_logo = false;
 
 uint8_t bcd_to_int(uint8_t val) {
     return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/part.h 
new/limine-12.4.0/common/lib/part.h
--- old/limine-12.3.3/common/lib/part.h 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/part.h 2026-07-01 23:50:19.000000000 +0200
@@ -55,6 +55,8 @@
     struct guid guid;
     bool part_guid_valid;
     struct guid part_guid;
+    bool part_type_guid_valid;
+    struct guid part_type_guid;
     bool fslabel_valid;
     char *fslabel;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/part.s2.c 
new/limine-12.4.0/common/lib/part.s2.c
--- old/limine-12.3.3/common/lib/part.s2.c      2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/lib/part.s2.c      2026-07-01 23:50:19.000000000 
+0200
@@ -302,17 +302,19 @@
 
     ret->part_guid_valid = true;
     ret->part_guid = entry.unique_partition_guid;
+    ret->part_type_guid_valid = true;
+    ret->part_type_guid = entry.partition_type_guid;
 
     return 0;
 }
 
 struct mbr_entry {
-       uint8_t status;
-       uint8_t chs_first_sect[3];
-       uint8_t type;
-       uint8_t chs_last_sect[3];
-       uint32_t first_sect;
-       uint32_t sect_count;
+    uint8_t status;
+    uint8_t chs_first_sect[3];
+    uint8_t type;
+    uint8_t chs_last_sect[3];
+    uint32_t first_sect;
+    uint32_t sect_count;
 } __attribute__((packed));
 
 bool is_valid_mbr(struct volume *volume) {
@@ -471,6 +473,7 @@
     }
 
     ret->part_guid_valid = false;
+    ret->part_type_guid_valid = false;
 
     return 0;
 }
@@ -575,6 +578,7 @@
     }
 
     ret->part_guid_valid = false;
+    ret->part_type_guid_valid = false;
 
     return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/pe.c 
new/limine-12.4.0/common/lib/pe.c
--- old/limine-12.3.3/common/lib/pe.c   2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/pe.c   2026-07-01 23:50:19.000000000 +0200
@@ -318,7 +318,7 @@
 
     if (is_reloc && kaslr) {
 again:
-        slide = (rand32() & ~(alignment - 1)) + (lower_to_higher ? 
FIXED_HIGHER_HALF_OFFSET_64 - image_base : 0);
+        slide = (safe_rand32() & ~(alignment - 1)) + (lower_to_higher ? 
FIXED_HIGHER_HALF_OFFSET_64 - image_base : 0);
 
         if (*virtual_base + slide + image_size < 0xffffffff80000000 /* this 
comparison relies on overflow */) {
             if (++try_count == max_simulated_tries) {
@@ -339,6 +339,12 @@
             panic(true, "pe: Section %U exceeds image bounds", (uint64_t)i);
         }
 
+        // The full VirtualSize (not just the raw size copied above) is mapped
+        // by the mem_range pass, so the whole virtual extent must fit too.
+        if ((uint64_t)section->VirtualAddress + section->VirtualSize > 
image_size) {
+            panic(true, "pe: Section %U virtual size exceeds image bounds", 
(uint64_t)i);
+        }
+
         // Validate section data doesn't exceed file bounds
         if ((uint64_t)section->PointerToRawData + section_raw_size > 
file_size) {
             panic(true, "pe: Section %U data extends beyond file bounds", 
(uint64_t)i);
@@ -412,7 +418,6 @@
                     case IMAGE_REL_BASED_DIR64: write_size = 8; break;
                     default:
                         panic(true, "pe: Unsupported relocation type %u", 
type);
-                        __builtin_unreachable();
                 }
 
                 if ((uint64_t)block->VirtualAddress + offset + write_size > 
image_size) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/print.s2.c 
new/limine-12.4.0/common/lib/print.s2.c
--- old/limine-12.3.3/common/lib/print.s2.c     2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/lib/print.s2.c     2026-07-01 23:50:19.000000000 
+0200
@@ -179,6 +179,10 @@
             case '#': {
                 bool printed = false;
                 char *str = (char *)va_arg(args, const char *);
+                if (!str) {
+                    prn_str(print_buf, &print_buf_i, "(null)");
+                    break;
+                }
                 for (int i = (int)strlen(str) - 1; i >= 0; i--) {
                     if (str[i] != '#') {
                         continue;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/rand.c 
new/limine-12.4.0/common/lib/rand.c
--- old/limine-12.3.3/common/lib/rand.c 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/rand.c 2026-07-01 23:50:19.000000000 +0200
@@ -3,137 +3,153 @@
 #include <stdbool.h>
 #include <lib/misc.h>
 #include <lib/print.h>
+#include <lib/libc.h>
 #include <lib/rand.h>
 #include <sys/cpu.h>
-#include <mm/pmm.h>
 
-// TODO: Find where this mersenne twister implementation is inspired from
-//       and properly credit the original author(s).
+// PCG32 (PCG-XSH-RR 64/32, single-stream variant) of M. E. O'Neill 2014.
+// For security-sensitive randomness use safe_rand32()/safe_rand64() instead.
 
-static bool rand_initialised = false;
+#define PCG_MULTIPLIER ((uint64_t)6364136223846793005)
+#define PCG_INCREMENT  ((uint64_t)1442695040888963407) // must be odd
 
-#define n ((int)624)
-#define m ((int)397)
-#define matrix_a ((uint32_t)0x9908b0df)
-#define msb ((uint32_t)0x80000000)
-#define lsbs ((uint32_t)0x7fffffff)
+static bool rand_initialised = false;
+static uint64_t pcg_state;
 
-static uint32_t *status;
-static int ctr;
+size_t hw_entropy(void *buf, size_t size) {
+    uint8_t *out = buf;
+    size_t filled = 0;
 
-static uint32_t hw_entropy(void) {
 #if defined (__x86_64__) || defined(__i386__)
     uint32_t eax, ebx, ecx, edx;
+    bool have_rdseed = cpuid(0x07, 0, &eax, &ebx, &ecx, &edx) && (ebx & (1 << 
18));
+    bool have_rdrand = cpuid(0x01, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 
30));
 
-    if (cpuid(0x07, 0, &eax, &ebx, &ecx, &edx) && (ebx & (1 << 18))) {
-        uint32_t val =
+    while (filled < size && (have_rdseed || have_rdrand)) {
+        uint32_t val;
+        if (have_rdseed) {
 #if defined (__x86_64__)
-            (uint32_t)rdseed(uint64_t); // Always do a 64-bit op on 64-bit to 
work around CPU bugs.
+            val = (uint32_t)rdseed(uint64_t); // Always do a 64-bit op on 
64-bit to work around CPU bugs.
 #elif defined (__i386__)
-            rdseed(uint32_t);
+            val = rdseed(uint32_t);
 #endif
-        if (val != 0) return val;
-    } else if (cpuid(0x01, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 30))) {
-        uint32_t val =
+        } else {
 #if defined (__x86_64__)
-            (uint32_t)rdrand(uint64_t); // As above.
+            val = (uint32_t)rdrand(uint64_t); // As above.
 #elif defined (__i386__)
-            rdrand(uint32_t);
+            val = rdrand(uint32_t);
 #endif
-        if (val != 0) return val;
+        }
+
+        // A zero result means the instruction never set carry across all of 
its
+        // retries; treat the source as exhausted rather than spinning forever.
+        if (val == 0) {
+            break;
+        }
+
+        size_t chunk = size - filled < sizeof(val) ? size - filled : 
sizeof(val);
+        memcpy(out + filled, &val, chunk);
+        filled += chunk;
     }
 #elif defined (__aarch64__)
     // ARMv8.5-RNG: check ID_AA64ISAR0_EL1 RNDR field (bits [63:60])
     uint64_t isar0;
     asm volatile ("mrs %0, id_aa64isar0_el1" : "=r" (isar0));
     if ((isar0 >> 60) & 0xf) {
-        uint64_t rndr;
-        // RNDR register: s3_3_c2_c4_0
-        bool ok;
-        asm volatile (
-            "mrs %0, s3_3_c2_c4_0\n\t"
-            "cset %w1, ne"
-            : "=r" (rndr), "=r" (ok)
-            :
-            : "cc"
-        );
-        if (ok) {
-            return (uint32_t)rndr;
+        while (filled < size) {
+            uint64_t rndr;
+            bool ok;
+            // RNDR register: s3_3_c2_c4_0
+            asm volatile (
+                "mrs %0, s3_3_c2_c4_0\n\t"
+                "cset %w1, ne"
+                : "=r" (rndr), "=r" (ok)
+                :
+                : "cc"
+            );
+            if (!ok) {
+                break;
+            }
+
+            size_t chunk = size - filled < sizeof(rndr) ? size - filled : 
sizeof(rndr);
+            memcpy(out + filled, &rndr, chunk);
+            filled += chunk;
         }
     }
 #endif
 
 #if defined (UEFI)
-    // Try EFI RNG protocol as a fallback for all UEFI platforms
-    {
+    // Try the EFI RNG protocol as a fallback for any bytes still missing.
+    if (filled < size) {
         EFI_GUID rng_guid = EFI_RNG_PROTOCOL_GUID;
         EFI_RNG_PROTOCOL *rng = NULL;
         if (gBS->LocateProtocol(&rng_guid, NULL, (void **)&rng) == EFI_SUCCESS 
&& rng != NULL) {
-            uint32_t val;
-            if (rng->GetRNG(rng, NULL, sizeof(val), (UINT8 *)&val) == 
EFI_SUCCESS) {
-                return val;
+            if (rng->GetRNG(rng, NULL, size - filled, out + filled) == 
EFI_SUCCESS) {
+                filled = size;
             }
         }
     }
 #endif
 
-    return 0;
+    return filled;
 }
 
-static void init_rand(void) {
-    uint32_t seed = ((uint32_t)0xc597060c * (uint32_t)rdtsc())
-                  * ((uint32_t)0xce86d624)
-                  ^ ((uint32_t)0xee0da130 * (uint32_t)rdtsc());
-
-    uint32_t hw = hw_entropy();
-    seed ^= hw;
-
-    status = ext_mem_alloc_counted(n, sizeof(uint32_t));
-
-    srand(seed);
+static uint32_t pcg_next(void) {
+    uint64_t old = pcg_state;
+    pcg_state = old * PCG_MULTIPLIER + PCG_INCREMENT;
+    uint32_t xorshifted = (uint32_t)(((old >> 18) ^ old) >> 27);
+    uint32_t rot = (uint32_t)(old >> 59);
+    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+}
 
+void srand(uint32_t s) {
+    // Canonical PCG seeding: advance, fold the seed in, advance again.
+    pcg_state = 0;
+    pcg_next();
+    pcg_state += s;
+    pcg_next();
     rand_initialised = true;
 }
 
-void srand(uint32_t s) {
-    status[0] = s;
-    for (ctr = 1; ctr < n; ctr++)
-        status[ctr] = (1812433253 * (status[ctr - 1] ^ (status[ctr - 1] >> 
30)) + ctr);
+static void init_rand(void) {
+    uint64_t seed = 0;
+    hw_entropy(&seed, sizeof(seed));
+    seed ^= (uint64_t)0xc597060cee0da130 * rdtsc();
+    seed ^= (uint64_t)0xce86d6249d2c5680 * rdtsc();
+    pcg_state = 0;
+    pcg_next();
+    pcg_state += seed;
+    pcg_next();
+    rand_initialised = true;
 }
 
 uint32_t rand32(void) {
     if (!rand_initialised)
         init_rand();
 
-    const uint32_t mag01[2] = {0, matrix_a};
-
-    if (ctr >= n) {
-        for (int kk = 0; kk < n - m; kk++) {
-            uint32_t y = (status[kk] & msb) | (status[kk + 1] & lsbs);
-            status[kk] = status[kk + m] ^ (y >> 1) ^ mag01[y & 1];
-        }
-
-        for (int kk = n - m; kk < n - 1; kk++) {
-            uint32_t y = (status[kk] & msb) | (status[kk + 1] & lsbs);
-            status[kk] = status[kk + (m - n)] ^ (y >> 1) ^ mag01[y & 1];
-        }
+    return pcg_next();
+}
 
-        uint32_t y = (status[n - 1] & msb) | (status[0] & lsbs);
-        status[n - 1] = status[m - 1] ^ (y >> 1) ^ mag01[y & 1];
+uint64_t rand64(void) {
+    return (((uint64_t)rand32()) << 32) | (uint64_t)rand32();
+}
 
-        ctr = 0;
+// Hardware-entropy-backed variants for security-sensitive consumers such as
+// ASLR. The PCG stream is deterministic given its seed and thus predictable if
+// any outputs leak; these return raw hardware entropy when available and fall
+// back to the PRNG only when no hardware source could provide the full width.
+uint32_t safe_rand32(void) {
+    uint32_t v;
+    if (hw_entropy(&v, sizeof(v)) == sizeof(v)) {
+        return v;
     }
-
-    uint32_t res = status[ctr++];
-
-    res ^= (res >> 11);
-    res ^= (res << 7) & 0x9d2c5680;
-    res ^= (res << 15) & 0xefc60000;
-    res ^= (res >> 18);
-
-    return res;
+    return rand32();
 }
 
-uint64_t rand64(void) {
-    return (((uint64_t)rand32()) << 32) | (uint64_t)rand32();
+uint64_t safe_rand64(void) {
+    uint64_t v;
+    if (hw_entropy(&v, sizeof(v)) == sizeof(v)) {
+        return v;
+    }
+    return rand64();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/lib/rand.h 
new/limine-12.4.0/common/lib/rand.h
--- old/limine-12.3.3/common/lib/rand.h 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/lib/rand.h 2026-07-01 23:50:19.000000000 +0200
@@ -2,10 +2,20 @@
 #define LIB__RAND_H__
 
 #include <stdint.h>
+#include <stddef.h>
 
-void srand(uint32_t s);
+/* Obtain hardware (cryptographically secure) entropy, filling up to size
+   bytes of buf. Returns the number of bytes actually filled. */
+size_t hw_entropy(void *buf, size_t size);
 
+/* Fast, C-like randomness API backed by PCG32. */
+void srand(uint32_t s);
 uint32_t rand32(void);
 uint64_t rand64(void);
 
+/* Hardware-entropy-backed variants for security-sensitive use (e.g. ASLR).
+   Fall back to the PRNG above when no hardware source is available. */
+uint32_t safe_rand32(void);
+uint64_t safe_rand64(void);
+
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/menu.c 
new/limine-12.4.0/common/menu.c
--- old/limine-12.3.3/common/menu.c     2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/menu.c     2026-07-01 23:50:19.000000000 +0200
@@ -327,7 +327,7 @@
     "GPT_GUID",
     "GPT_UUID",
     "IMAGE_PATH",
-       "DTB_PATH",
+    "DTB_PATH",
     "ENTRY",
     "IF_FW_TYPE",
     "IF_ARCH",
@@ -613,7 +613,7 @@
                     print("%c", tab_space_count ? ' ' : buffer[i]);
                 }
 
-               if (tab_space_count != 0) {
+                if (tab_space_count != 0) {
                     tab_space_count--;
                 }
             }
@@ -1295,6 +1295,24 @@
 }
 #endif
 
+static void print_entry_comment(const struct menu_entry *entry, size_t row) {
+    if (entry->comment == NULL) {
+        return;
+    }
+
+    size_t comment_len = strlen(entry->comment);
+    size_t max_len = terms[0]->cols - 2;
+    FOR_TERM(TERM->scroll_enabled = false);
+    if (comment_len <= max_len) {
+        set_cursor_pos_helper((terms[0]->cols - comment_len) / 2, row);
+        print("\e[36m%s\e[0m", entry->comment);
+    } else {
+        set_cursor_pos_helper(1, row);
+        print("\e[36m%S...\e[0m", entry->comment, (size_t)(max_len - 3));
+    }
+    FOR_TERM(TERM->scroll_enabled = true);
+}
+
 noreturn void _menu(bool first_run) {
     size_t data_size = (uintptr_t)data_end - (uintptr_t)data_begin;
 #if defined (BIOS)
@@ -1358,6 +1376,9 @@
     char *quiet_str = config_get_value(NULL, 0, "QUIET");
     quiet = quiet_str != NULL && strcmp(quiet_str, "yes") == 0;
 
+    char *firmware_logo_str = config_get_value(NULL, 0, "FIRMWARE_LOGO");
+    firmware_logo = firmware_logo_str != NULL && strcmp(firmware_logo_str, 
"yes") == 0;
+
     char *verbose_str = config_get_value(NULL, 0, "VERBOSE");
     verbose = verbose_str != NULL && strcmp(verbose_str, "yes") == 0;
 
@@ -1830,6 +1851,7 @@
 
     if (skip_timeout == false) {
         print("\n\n");
+        print_entry_comment(selected_menu_entry, terms[0]->rows - 3);
         while (timeout_ms != 0) {
             char timeout_buf[24];
             uint64_t sleep_ms = timeout_ms % 1000;
@@ -1862,18 +1884,8 @@
         goto autoboot;
     }
 
-    if (max_entries != 0 && selected_menu_entry->comment != NULL) {
-        size_t comment_len = strlen(selected_menu_entry->comment);
-        size_t max_len = terms[0]->cols - 2;
-        FOR_TERM(TERM->scroll_enabled = false);
-        if (comment_len <= max_len) {
-            set_cursor_pos_helper((terms[0]->cols - comment_len) / 2, 
terms[0]->rows - 2);
-            print("\e[36m%s\e[0m", selected_menu_entry->comment);
-        } else {
-            set_cursor_pos_helper(1, terms[0]->rows - 2);
-            print("\e[36m%S...\e[0m", selected_menu_entry->comment, 
(size_t)(max_len - 3));
-        }
-        FOR_TERM(TERM->scroll_enabled = true);
+    if (max_entries != 0) {
+        print_entry_comment(selected_menu_entry, terms[0]->rows - 2);
     }
 
     if (booting_from_editor) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/mm/mtrr.c 
new/limine-12.4.0/common/mm/mtrr.c
--- old/limine-12.3.3/common/mm/mtrr.c  2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/mm/mtrr.c  2026-07-01 23:50:19.000000000 +0200
@@ -41,7 +41,7 @@
     ) * sizeof(uint64_t));
 
     /* save variable range MTRRs */
-    for (uint8_t i = 0; i < var_reg_count * 2; i += 2) {
+    for (unsigned i = 0; i < (unsigned)var_reg_count * 2; i += 2) {
         saved_mtrrs[i] = rdmsr(0x200 + i);
         saved_mtrrs[i + 1] = rdmsr(0x200 + i + 1);
     }
@@ -111,7 +111,7 @@
     wrmsr(0x2ff, mtrr_def);
 
     /* restore variable range MTRRs */
-    for (uint8_t i = 0; i < var_reg_count * 2; i += 2) {
+    for (unsigned i = 0; i < (unsigned)var_reg_count * 2; i += 2) {
         wrmsr(0x200 + i, saved_mtrrs[i]);
         wrmsr(0x200 + i + 1, saved_mtrrs[i + 1]);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/protos/chainload.c 
new/limine-12.4.0/common/protos/chainload.c
--- old/limine-12.3.3/common/protos/chainload.c 2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/protos/chainload.c 2026-07-01 23:50:19.000000000 
+0200
@@ -3,6 +3,7 @@
 #include <stdnoreturn.h>
 #include <protos/chainload.h>
 #include <lib/part.h>
+#include <lib/guid.h>
 #include <lib/config.h>
 #include <lib/misc.h>
 #include <drivers/disk.h>
@@ -81,6 +82,15 @@
     __builtin_unreachable();
 }
 
+// Defined in spinup_freebsd.asm_bios_ia32.
+noreturn void spinup_freebsd(uint32_t drive, uint32_t buf, uint32_t count);
+
+// FreeBSD's freebsd-boot partition contains gptboot, a multi-sector binary 
with
+// no MBR signature that FreeBSD's pmbr loads whole to 0x7C00. Cap prevents
+// EBDA overwrite.
+#define FREEBSD_BOOT_TYPE_GUID "83bd6b9d-7f41-11dc-be0b-001560b84f0f"
+#define FREEBSD_BOOT_LOAD_MAX 0x80000
+
 noreturn void chainload(char *config, char *cmdline) {
     (void)cmdline;
 
@@ -187,6 +197,29 @@
 load:
     vga_textmode_init(false);
 
+    // A freebsd-boot partition is not a normal boot record, it holds
+    // gptboot, which has no 0xAA55 signature and is loaded whole by FreeBSD's
+    // pmbr. Detect it by GPT type GUID and emulate the handoff.
+    struct guid freebsd_boot_guid;
+    if (p->part_type_guid_valid
+     && string_to_guid_mixed(&freebsd_boot_guid, FREEBSD_BOOT_TYPE_GUID)
+     && memcmp(&p->part_type_guid, &freebsd_boot_guid, sizeof(struct guid)) == 
0) {
+        uint64_t load_size = (uint64_t)p->sect_count * 
(uint64_t)p->sector_size;
+        if (load_size > FREEBSD_BOOT_LOAD_MAX) {
+            load_size = FREEBSD_BOOT_LOAD_MAX;
+        }
+        if (load_size == 0) {
+            panic(true, "bios: freebsd-boot partition has zero size");
+        }
+
+        void *fbuf = ext_mem_alloc(load_size);
+        if (!volume_read(p, fbuf, 0, load_size)) {
+            panic(true, "bios: Failed to read freebsd-boot partition");
+        }
+
+        spinup_freebsd(p->drive, (uint32_t)(uintptr_t)fbuf, 
(uint32_t)load_size);
+    }
+
     void *buf = ext_mem_alloc(512);
 
     if (!volume_read(p, buf, 0, 512)) {
@@ -233,6 +266,10 @@
     size_t end_item_len      = sizeof(EFI_DEVICE_PATH_PROTOCOL);
     size_t alloc_len         = path_item_len + end_item_len;
 
+    if (path_item_len > 0xffff) {
+        panic(true, "efi: Image path too long for device path node");
+    }
+
     EFI_DEVICE_PATH_PROTOCOL *device_path;
     EFI_STATUS status = gBS->AllocatePool(EfiLoaderData, alloc_len, (void 
**)&device_path);
     if (status) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/protos/limine.c 
new/limine-12.4.0/common/protos/limine.c
--- old/limine-12.3.3/common/protos/limine.c    2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/protos/limine.c    2026-07-01 23:50:19.000000000 
+0200
@@ -354,7 +354,7 @@
     if (randomise_hhdm_base) {
         // A quarter of the higher half of wiggle room for KASLR, align to 
1GiB steps.
         uint64_t mask = ((uint64_t)1 << (paging_mode_va_bits(paging_mode) - 
3)) - 1;
-        direct_map_offset += (rand64() & ~((uint64_t)0x40000000 - 1)) & mask;
+        direct_map_offset += (safe_rand64() & ~((uint64_t)0x40000000 - 1)) & 
mask;
     }
 }
 
@@ -1226,7 +1226,7 @@
             module_cmdline = (char *)get_phys_addr(internal_module->string);
 
             bool module_compressed = internal_module->flags & 
LIMINE_INTERNAL_MODULE_COMPRESSED;
-            
+
             // Validate path length to prevent buffer overflow
             size_t k_resource_len = strlen(k_resource);
             size_t k_root_len = strlen(k_root);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/protos/linux_risc.c 
new/limine-12.4.0/common/protos/linux_risc.c
--- old/limine-12.3.3/common/protos/linux_risc.c        2026-06-09 
08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/protos/linux_risc.c        2026-07-01 
23:50:19.000000000 +0200
@@ -139,7 +139,12 @@
             panic(true, "linux: failed to open module `%s`. Is the path 
correct?", module_path);
         }
 
-        total_size = CHECKED_ADD(total_size, module_file->size,
+        // Align each module to 4 bytes so the kernel's initramfs unpacker,
+        // which only accepts a raw cpio header at a 4-byte aligned offset,
+        // can find concatenated archives.
+        size_t module_size = ALIGN_UP(module_file->size, 4,
+            panic(true, "linux: Total module size overflow"));
+        total_size = CHECKED_ADD(total_size, module_size,
             panic(true, "linux: Total module size overflow"));
 
         modules[i] = module_file;
@@ -164,7 +169,8 @@
 
         printv("linux: loaded module `%s` at %p, size %U\n", module_path,
                p->module_base + offset, (uint64_t)module_size);
-        offset += module_size;
+        offset += ALIGN_UP(module_size, 4,
+            panic(true, "linux: Total module size overflow"));
     }
 
     pmm_free(modules, module_count * sizeof(struct file_handle *));
@@ -261,7 +267,6 @@
 }
 
 static void prepare_efi_tables(struct boot_param *p, char *config) {
-    (void)p;
     EFI_STATUS ret = 0;
 
     {
@@ -380,13 +385,13 @@
         EFI_MEMORY_DESCRIPTOR *entry = (void *)efi_mmap + i * efi_desc_size;
 
         if (entry->Attribute & EFI_MEMORY_RUNTIME) {
-           // LoongArch kernel requires the virtual address stays in the
-           // privileged, direct-mapped window
-           #if defined(__loongarch__)
-                       entry->VirtualStart = entry->PhysicalStart | (0x8ULL << 
60);
+            // LoongArch kernel requires the virtual address stays in the
+            // privileged, direct-mapped window
+            #if defined(__loongarch__)
+                entry->VirtualStart = entry->PhysicalStart | (0x8ULL << 60);
             #else
-               entry->VirtualStart = entry->PhysicalStart;
-           #endif
+                entry->VirtualStart = entry->PhysicalStart;
+            #endif
         }
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/protos/linux_x86.c 
new/limine-12.4.0/common/protos/linux_x86.c
--- old/limine-12.3.3/common/protos/linux_x86.c 2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/protos/linux_x86.c 2026-07-01 23:50:19.000000000 
+0200
@@ -408,6 +408,9 @@
     uintptr_t kernel_align = 0x100000;
     if (setup_header->version >= 0x205 && setup_header->kernel_alignment > 
kernel_align) {
         kernel_align = setup_header->kernel_alignment;
+        if ((kernel_align & (kernel_align - 1)) != 0) {
+            panic(true, "linux: kernel_alignment is not a power of two");
+        }
     }
     // Start at pref_address: the decompressor relocates itself up to
     // LOAD_PHYSICAL_ADDR (= pref_address) and scribbles init_size bytes from
@@ -485,7 +488,12 @@
         )) == NULL)
             panic(true, "linux: Failed to open module with path `%s`. Is the 
path correct?", module_path);
 
-        size_of_all_modules = CHECKED_ADD(size_of_all_modules, module->size,
+        // Align each module to 4 bytes so the kernel's initramfs unpacker,
+        // which only accepts a raw cpio header at a 4-byte aligned offset,
+        // can find concatenated archives.
+        size_t module_size = ALIGN_UP(module->size, 4,
+            panic(true, "linux: Total module size overflow"));
+        size_of_all_modules = CHECKED_ADD(size_of_all_modules, module_size,
             panic(true, "linux: Total module size overflow"));
 
         modules[i] = module;
@@ -535,15 +543,21 @@
         if (module_path == NULL)
             break;
 
-        fread(modules[i], (void *)_modules_mem_base, 0, modules[i]->size);
+        size_t module_size = modules[i]->size;
+        size_t padded_size = ALIGN_UP(module_size, 4,
+            panic(true, "linux: Total module size overflow"));
+
+        fread(modules[i], (void *)_modules_mem_base, 0, module_size);
+        memset((void *)(_modules_mem_base + module_size), 0,
+               padded_size - module_size);
 
 #if defined (UEFI)
         tpm_measure_path(TPM_PCR_BOOT_AUTH, TPM_EV_IPL, "module_path: ", 
module_path);
         tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
-                    (void *)_modules_mem_base, modules[i]->size, "module_path: 
", module_path);
+                    (void *)_modules_mem_base, module_size, "module_path: ", 
module_path);
 #endif
 
-        _modules_mem_base += modules[i]->size;
+        _modules_mem_base += padded_size;
 
         fclose(modules[i]);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/protos/multiboot2.c 
new/limine-12.4.0/common/protos/multiboot2.c
--- old/limine-12.3.3/common/protos/multiboot2.c        2026-06-09 
08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/protos/multiboot2.c        2026-07-01 
23:50:19.000000000 +0200
@@ -173,6 +173,9 @@
         if (tag->size == 0) {
             break;
         }
+        if (tag->size > (size_t)((uintptr_t)header + header->header_length - 
(uintptr_t)tag)) {
+            panic(true, "multiboot2: Header tag exceeds header bounds");
+        }
         size_t tag_stride = ALIGN_UP(tag->size, MULTIBOOT_TAG_ALIGN, break);
         bool is_required = !(tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL);
         switch (tag->type) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/limine-12.3.3/common/protos/spinup_freebsd.asm_bios_ia32 
new/limine-12.4.0/common/protos/spinup_freebsd.asm_bios_ia32
--- old/limine-12.3.3/common/protos/spinup_freebsd.asm_bios_ia32        
1970-01-01 01:00:00.000000000 +0100
+++ new/limine-12.4.0/common/protos/spinup_freebsd.asm_bios_ia32        
2026-07-01 23:50:19.000000000 +0200
@@ -0,0 +1,87 @@
+; Hand off to a FreeBSD `gptboot` blob the way FreeBSD's `pmbr` does.
+;
+; The blob has already been read into a high buffer. It must end up at 0x7C00,
+; but copying it there overwrites the running bootloader (linked at 0xf000) and
+; its GDT. Relocate a small copier to 0x600; (below the copy destination, where
+; it survives), copy the blob down in protected mode, then transition to real
+; mode using a self-contained GDT and jump to the blob with DL = drive.
+;
+; noreturn void spinup_freebsd(uint32_t drive, uint32_t buf, uint32_t count);
+
+%define RELOC 0x0600
+%define AT(label) (RELOC + ((label) - payload_begin))
+
+section .text
+
+bits 32
+global spinup_freebsd
+spinup_freebsd:
+    cli
+    cld
+
+    mov edx, [esp + 4]                 ; drive (DL)
+    mov esi, [esp + 8]                 ; buf (high source)
+    mov ecx, [esp + 12]                ; count (bytes)
+
+    ; Relocate to 0x600.
+    push esi
+    push ecx
+    mov esi, payload_begin
+    mov edi, RELOC
+    mov ecx, payload_end - payload_begin
+    rep movsb
+    pop ecx
+    pop esi
+
+    jmp AT(payload_begin)        ; branch to relocated copier in 32-bit PM
+
+; relocatable payload that executes at 0x600:
+; In: ESI = source, ECX = byte count, EDX = drive (DL). DS/ES flat.
+payload_begin:
+    bits 32
+    mov edi, 0x7c00
+    rep movsb                    ; flat PM copy of the whole blob, any size
+
+    lgdt [AT(gdtr)]              ; self-contained GDT
+    lidt [AT(rm_idt)]            ; real-mode IVT
+
+    jmp 0x08:AT(.pm16)           ; Far jump to 16-bit PM.
+.pm16:
+    bits 16
+    mov ax, 0x10
+    mov ds, ax
+    mov es, ax
+    mov ss, ax
+    mov eax, cr0
+    and al, 0xfe
+    mov cr0, eax
+    jmp 0x0000:AT(.real)        ; enter real mode
+.real:
+    xor ax, ax
+    mov ds, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+    mov ss, ax
+    mov sp, 0x7c00
+    sti
+    jmp 0x0000:0x7c00           ; DL is still drive
+
+    bits 32
+align 8
+gdt:
+    dq 0                        ; null
+    dw 0xffff, 0x0000           ; 0x08: 16-bit code, base 0, limit 0xffff
+    db 0x00, 10011011b, 00000000b, 0x00
+    dw 0xffff, 0x0000           ; 0x10: 16-bit data, base 0, limit 0xffff
+    db 0x00, 10010011b, 00000000b, 0x00
+gdt_end:
+gdtr:
+    dw gdt_end - gdt - 1
+    dd AT(gdt)
+rm_idt:
+    dw 0x3ff
+    dd 0
+payload_end:
+
+section .note.GNU-stack noalloc noexec nowrite progbits
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/pxe/pxe.s2.c 
new/limine-12.4.0/common/pxe/pxe.s2.c
--- old/limine-12.3.3/common/pxe/pxe.s2.c       2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/pxe/pxe.s2.c       2026-07-01 23:50:19.000000000 
+0200
@@ -34,9 +34,9 @@
         panic(false, "PXE installation check failed");
     }
 
-    struct pxenv* pxenv = { 0 };
+    struct pxenv *pxenv = NULL;
 
-    pxenv = (struct pxenv*)((r.es << 4) + (r.ebx & 0xffff));
+    pxenv = (struct pxenv *)((r.es << 4) + (r.ebx & 0xffff));
     if (memcmp(pxenv->signature, PXE_SIGNATURE, sizeof(pxenv->signature)) != 
0) {
         panic(false, "PXENV structure signature corrupted");
     }
@@ -46,7 +46,7 @@
         panic(false, "pxe version too old");
     }
 
-    struct bangpxe* bangpxe = (struct bangpxe*)((((pxenv->pxe_ptr & 
0xffff0000) >> 16) << 4) + (pxenv->pxe_ptr & 0xffff));
+    struct bangpxe *bangpxe = (struct bangpxe *)((((pxenv->pxe_ptr & 
0xffff0000) >> 16) << 4) + (pxenv->pxe_ptr & 0xffff));
 
     if (memcmp(bangpxe->signature, PXE_BANGPXE_SIGNATURE,
             sizeof(bangpxe->signature))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/pxe/tftp.s2.c 
new/limine-12.4.0/common/pxe/tftp.s2.c
--- old/limine-12.3.3/common/pxe/tftp.s2.c      2026-06-09 08:21:35.000000000 
+0200
+++ new/limine-12.4.0/common/pxe/tftp.s2.c      2026-07-01 23:50:19.000000000 
+0200
@@ -144,7 +144,7 @@
         }
 
         // Validate read size doesn't overflow the buffer (use alloc_mtu, not 
server's mtu)
-        if (read.bsize > alloc_mtu || progress + read.bsize > handle->size) {
+        if (read.bsize > alloc_mtu || read.bsize > handle->size - progress) {
             panic(false, "tftp: Server sent more data than expected");
         }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/common/sys/smp.c 
new/limine-12.4.0/common/sys/smp.c
--- old/limine-12.3.3/common/sys/smp.c  2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/common/sys/smp.c  2026-07-01 23:50:19.000000000 +0200
@@ -930,21 +930,21 @@
 }
 
 static void csr_mail_send(uint64_t data, int cpu, int mailbox) {
-       uint64_t val;
+    uint64_t val;
 
     // High 32bit
-       val = ((uint64_t)1 << IOCSR_MBUF_SEND_BLOCKING_BIT);
-       val |= (((mailbox << 1) + 1) << IOCSR_MBUF_SEND_BOX_SHIFT);
-       val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT);
-       val |= (data & 0xFFFFFFFF00000000);
-       iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND);
+    val = ((uint64_t)1 << IOCSR_MBUF_SEND_BLOCKING_BIT);
+    val |= (((mailbox << 1) + 1) << IOCSR_MBUF_SEND_BOX_SHIFT);
+    val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT);
+    val |= (data & 0xFFFFFFFF00000000);
+    iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND);
 
     // Low 32bit
-       val = ((uint64_t)1 << IOCSR_MBUF_SEND_BLOCKING_BIT);
-       val |= ((mailbox << 1) << IOCSR_MBUF_SEND_BOX_SHIFT);
-       val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT);
-       val |= (data << 32);
-       iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND);
+    val = ((uint64_t)1 << IOCSR_MBUF_SEND_BLOCKING_BIT);
+    val |= ((mailbox << 1) << IOCSR_MBUF_SEND_BOX_SHIFT);
+    val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT);
+    val |= (data << 32);
+    iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND);
 };
 
 static void smp_send_ipi(uint32_t phys_id, uint32_t action) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/configure new/limine-12.4.0/configure
--- old/limine-12.3.3/configure 2026-06-09 08:21:39.000000000 +0200
+++ new/limine-12.4.0/configure 2026-07-01 23:50:27.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.73 for Limine 12.3.3.
+# Generated by GNU Autoconf 2.73 for Limine 12.4.0.
 #
 # Report bugs to <https://github.com/Limine-Bootloader/Limine/issues>.
 #
@@ -589,8 +589,8 @@
 # Identity of this package.
 PACKAGE_NAME='Limine'
 PACKAGE_TARNAME='limine'
-PACKAGE_VERSION='12.3.3'
-PACKAGE_STRING='Limine 12.3.3'
+PACKAGE_VERSION='12.4.0'
+PACKAGE_STRING='Limine 12.4.0'
 PACKAGE_BUGREPORT='https://github.com/Limine-Bootloader/Limine/issues'
 PACKAGE_URL='https://limine-bootloader.org/'
 
@@ -1318,7 +1318,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures Limine 12.3.3 to adapt to many kinds of systems.
+'configure' configures Limine 12.4.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1384,7 +1384,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Limine 12.3.3:";;
+     short | recursive ) echo "Configuration of Limine 12.4.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1504,7 +1504,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Limine configure 12.3.3
+Limine configure 12.4.0
 generated by GNU Autoconf 2.73
 
 Copyright (C) 2026 Free Software Foundation, Inc.
@@ -1655,7 +1655,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Limine $as_me 12.3.3, which was
+It was created by Limine $as_me 12.4.0, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -7863,7 +7863,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Limine $as_me 12.3.3, which was
+This file was extended by Limine $as_me 12.4.0, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7919,7 +7919,7 @@
 cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-Limine config.status 12.3.3
+Limine config.status 12.4.0
 configured by $0, generated by GNU Autoconf 2.73,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/timestamps new/limine-12.4.0/timestamps
--- old/limine-12.3.3/timestamps        2026-06-09 08:21:37.000000000 +0200
+++ new/limine-12.4.0/timestamps        2026-07-01 23:50:23.000000000 +0200
@@ -1,3 +1,3 @@
-REGEN_DATE="June 2026"
-SOURCE_DATE_EPOCH="1780985602"
-SOURCE_DATE_EPOCH_TOUCH="202606090813"
+REGEN_DATE="July 2026"
+SOURCE_DATE_EPOCH="1782940570"
+SOURCE_DATE_EPOCH_TOUCH="202607012316"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/tools/limlzpack.c 
new/limine-12.4.0/tools/limlzpack.c
--- old/limine-12.3.3/tools/limlzpack.c 2026-06-09 08:21:35.000000000 +0200
+++ new/limine-12.4.0/tools/limlzpack.c 2026-07-01 23:50:19.000000000 +0200
@@ -1,16 +1,16 @@
 /* limlz: Copyright (C) 2026 Kamila Szewczyk <[email protected]>
  * limine: Copyright (C) 2019-2026 Mintsuki and contributors.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright notice, 
this
  *    list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -22,7 +22,7 @@
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #include <stdint.h>
 #include <stddef.h>
 #include <stdlib.h>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/limine-12.3.3/version new/limine-12.4.0/version
--- old/limine-12.3.3/version   2026-06-09 08:21:39.000000000 +0200
+++ new/limine-12.4.0/version   2026-07-01 23:50:27.000000000 +0200
@@ -1 +1 @@
-12.3.3
+12.4.0

Reply via email to