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
