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-05-27 16:20:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/limine (Old) and /work/SRC/openSUSE:Factory/.limine.new.1937 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "limine" Wed May 27 16:20:29 2026 rev:42 rq:1355323 version:12.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/limine/limine.changes 2026-05-10 16:49:22.015339369 +0200 +++ /work/SRC/openSUSE:Factory/.limine.new.1937/limine.changes 2026-05-27 16:20:45.006208580 +0200 @@ -1,0 +2,14 @@ +Wed May 27 09:18:45 UTC 2026 - Marvin Friedrich <[email protected]> + +- Update to 12.3.1: + * Add support for fractional timeout values. + * Significantly improve framebuffer performance on some machines by + using the Write Combining caching mode via PAT and page tables on + x86-64/UEFI instead of MTRRs. + * Improve reliability of the MTRR framebuffer Write Combining path on + IA-32 (UEFI and BIOS). + * Fix x86(_64) Linux protocol loader miscompliance that could cause + boot failures on some setups showing an "invalid magic at start of + compressed archive" error. + +------------------------------------------------------------------- Old: ---- limine-12.2.0.tar.gz New: ---- limine-12.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ limine.spec ++++++ --- /var/tmp/diff_new_pack.oghxCa/_old 2026-05-27 16:20:46.186256868 +0200 +++ /var/tmp/diff_new_pack.oghxCa/_new 2026-05-27 16:20:46.190257031 +0200 @@ -15,7 +15,7 @@ # Name: limine -Version: 12.2.0 +Version: 12.3.1 Release: 0 Summary: Modern, advanced, portable, multiprotocol bootloader and boot manager License: BSD-2-Clause ++++++ limine-12.2.0.tar.gz -> limine-12.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/CONFIG.md new/limine-12.3.1/CONFIG.md --- old/limine-12.2.0/CONFIG.md 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/CONFIG.md 2026-05-24 18:16:54.000000000 +0200 @@ -75,8 +75,9 @@ Miscellaneous: * `timeout` - Specifies the timeout in seconds before the first *entry* is - automatically booted. If set to `no`, disable automatic boot. If set to `0`, - boots default entry instantly (see `default_entry` option). + automatically booted. Decimal values such as `0.25` are accepted. If set to + `no`, disable automatic boot. If set to `0`, boots default entry instantly + (see `default_entry` option). * `quiet` - If set to `yes`, enable quiet mode, where all screen output except panics and important warnings is suppressed. If `timeout` is not 0, the `timeout` still occurs, and pressing any key during the timeout will reveal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/ChangeLog new/limine-12.3.1/ChangeLog --- old/limine-12.2.0/ChangeLog 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/ChangeLog 2026-05-24 18:16:54.000000000 +0200 @@ -1,3 +1,34 @@ +2026-05-24 Mintsuki <[email protected]> + + *** Release 12.3.1 *** + + Noteworthy changes compared to the previous release, 12.3.0: + + Bug fixes: + - Fix x86(_64) Linux protocol loader miscompliance that could cause + boot failures on some setups showing an "invalid magic at start of + compressed archive" error. + + Miscellaneous: + - Shrink the size of `limine-uefi-cd.bin` to avoid wasting space when + unnecessary. + +2026-05-18 Mintsuki <[email protected]> + + *** Release 12.3.0 *** + + Noteworthy changes compared to the previous release, 12.2.0: + + New features: + - Add support for fractional timeout values. + + Miscellaneous: + - Significantly improve framebuffer performance on some machines by + using the Write Combining caching mode via PAT and page tables on + x86-64/UEFI instead of MTRRs. + - Improve reliability of the MTRR framebuffer Write Combining path on + IA-32 (UEFI and BIOS). + 2026-05-07 Mintsuki <[email protected]> *** Release 12.2.0 *** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/GNUmakefile.in new/limine-12.3.1/GNUmakefile.in --- old/limine-12.2.0/GNUmakefile.in 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/GNUmakefile.in 2026-05-24 18:16:54.000000000 +0200 @@ -208,8 +208,6 @@ ifneq ($(BUILD_UEFI_CD),no) $(MKDIR_P) '$(call SHESCAPE,$(BINDIR))' rm -f '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' - dd if=/dev/zero of='$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' bs=512 count=32768 2>/dev/null - mformat -i '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' -h 64 -t 32 -s 16 -N 12345678 :: LIMINE_UEFI_CD_TMP="$$(mktemp -d)"; \ mkdir -p "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ @@ -218,6 +216,9 @@ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ find "$$LIMINE_UEFI_CD_TMP" -exec touch -t $(SOURCE_DATE_EPOCH_TOUCH) '{}' + && \ + LIMINE_UEFI_CD_SIZE="$$(du -sk "$$LIMINE_UEFI_CD_TMP" | $(AWK) '{ print $$1 }')" && \ + LIMINE_UEFI_CD_SECTORS="$$(( (($$LIMINE_UEFI_CD_SIZE + 1023) / 1024 + 1) * 2048 ))" && \ + mformat -C -i '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' -T "$$LIMINE_UEFI_CD_SECTORS" -N 12345678 :: && \ mcopy -D o -s -m -i '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' "$$LIMINE_UEFI_CD_TMP"/EFI :: && \ rm -rf "$$LIMINE_UEFI_CD_TMP" endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/SECURITY.md new/limine-12.3.1/SECURITY.md --- old/limine-12.2.0/SECURITY.md 1970-01-01 01:00:00.000000000 +0100 +++ new/limine-12.3.1/SECURITY.md 2026-05-24 18:16:54.000000000 +0200 @@ -0,0 +1,15 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 12.x | :white_check_mark: | + +## Reporting a Vulnerability + +Please, strongly consider reporting security vulnerabilities privately using the [advisories page](https://github.com/Limine-Bootloader/Limine/security/advisories). + +**Allow the maintainers up to 30 days to address the vulnerability and make a new release containing the fix before going public with it.** + +If going public with it after 30 days with the issue still unpatched, opening a public issue referencing the advisory is recommended. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/drivers/gop.c new/limine-12.3.1/common/drivers/gop.c --- old/limine-12.2.0/common/drivers/gop.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/drivers/gop.c 2026-05-24 18:16:54.000000000 +0200 @@ -126,8 +126,7 @@ static bool try_mode(struct fb_info *ret, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, size_t mode, uint64_t width, uint64_t height, int bpp, - struct fb_info *fbs, size_t fbs_count, - bool preserve_screen) { + struct fb_info *fbs, size_t fbs_count) { EFI_STATUS status; if (!mode_to_fb_info(ret, gop, mode)) { @@ -179,10 +178,6 @@ ret->framebuffer_addr = gop->Mode->FrameBufferBase; - if (!preserve_screen) { - fb_clear(ret); - } - return true; } @@ -213,8 +208,7 @@ no_unwind static bool preset_modes_initialised = false; void init_gop(struct fb_info **ret, size_t *_fbs_count, - uint64_t target_width, uint64_t target_height, uint16_t target_bpp, - bool preserve_screen) { + uint64_t target_width, uint64_t target_height, uint16_t target_bpp) { if (preset_modes_initialised == false) { for (size_t i = 0; i < MAX_PRESET_MODES; i++) { preset_modes[i] = -1; @@ -321,7 +315,7 @@ retry: for (size_t j = 0; j < modes_count; j++) { - if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count, preserve_screen)) { + if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count)) { goto success; } } @@ -348,7 +342,7 @@ if (current_fallback == 1) { current_fallback++; - if (try_mode(fb, gop, preset_modes[i], 0, 0, 0, *ret, fbs_count, preserve_screen)) { + if (try_mode(fb, gop, preset_modes[i], 0, 0, 0, *ret, fbs_count)) { goto success; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/drivers/gop.h new/limine-12.3.1/common/drivers/gop.h --- old/limine-12.2.0/common/drivers/gop.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/drivers/gop.h 2026-05-24 18:16:54.000000000 +0200 @@ -9,8 +9,7 @@ #include <lib/fb.h> void init_gop(struct fb_info **ret, size_t *_fbs_count, - uint64_t target_width, uint64_t target_height, uint16_t target_bpp, - bool preserve_screen); + uint64_t target_width, uint64_t target_height, uint16_t target_bpp); extern bool gop_force_16; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/drivers/vbe.c new/limine-12.3.1/common/drivers/vbe.c --- old/limine-12.2.0/common/drivers/vbe.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/drivers/vbe.c 2026-05-24 18:16:54.000000000 +0200 @@ -231,8 +231,7 @@ } bool init_vbe(struct fb_info *ret, - uint16_t target_width, uint16_t target_height, uint16_t target_bpp, - bool preserve_screen) { + uint16_t target_width, uint16_t target_height, uint16_t target_bpp) { printv("vbe: Initialising...\n"); size_t current_fallback = 0; @@ -344,10 +343,6 @@ continue; } - if (!preserve_screen) { - fb_clear(ret); - } - return true; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/drivers/vbe.h new/limine-12.3.1/common/drivers/vbe.h --- old/limine-12.2.0/common/drivers/vbe.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/drivers/vbe.h 2026-05-24 18:16:54.000000000 +0200 @@ -7,8 +7,7 @@ #include <lib/fb.h> bool init_vbe(struct fb_info *ret, - uint16_t target_width, uint16_t target_height, uint16_t target_bpp, - bool preserve_screen); + uint16_t target_width, uint16_t target_height, uint16_t target_bpp); struct fb_info *vbe_get_mode_list(size_t *count); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/fb.c new/limine-12.3.1/common/lib/fb.c --- old/limine-12.2.0/common/lib/fb.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/fb.c 2026-05-24 18:16:54.000000000 +0200 @@ -6,6 +6,8 @@ #include <drivers/vbe.h> #include <drivers/gop.h> #include <mm/pmm.h> +#include <mm/mtrr.h> +#include <mm/efi_pt.h> #include <sys/cpu.h> struct fb_info *fb_fbs; @@ -13,14 +15,14 @@ void fb_init(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp, - bool preserve_screen) { + bool preserve_screen, bool keep_wc) { if (quiet) { preserve_screen = true; } #if defined (BIOS) *ret = ext_mem_alloc(sizeof(struct fb_info)); - if (init_vbe(*ret, target_width, target_height, target_bpp, preserve_screen)) { + if (init_vbe(*ret, target_width, target_height, target_bpp)) { *_fbs_count = 1; (*ret)->edid = get_edid_info(); @@ -32,11 +34,50 @@ pmm_free(*ret, sizeof(struct fb_info)); } #elif defined (UEFI) - init_gop(ret, _fbs_count, target_width, target_height, target_bpp, preserve_screen); + init_gop(ret, _fbs_count, target_width, target_height, target_bpp); #endif fb_fbs = *ret; fb_fbs_count = *_fbs_count; + + // Map the framebuffers as write-combining so the clear (and, when kept, + // terminal rendering) is fast. keep_wc leaves it active for the caller. + bool want_wc = keep_wc || !preserve_screen; + +#if defined (__i386__) || defined (__x86_64__) + if (want_wc) { + for (size_t i = 0; i < *_fbs_count; i++) { + uint64_t fb_size = (uint64_t)(*ret)[i].framebuffer_pitch + * (*ret)[i].framebuffer_height; + if (fb_size == 0) { + continue; + } +#if defined (__x86_64__) && defined (UEFI) + efi_pt_set_fb_wc((*ret)[i].framebuffer_addr, fb_size); +#else + mtrr_wc_add_fb_range((*ret)[i].framebuffer_addr, fb_size); +#endif + } + } +#endif + + if (!preserve_screen) { + for (size_t i = 0; i < *_fbs_count; i++) { + fb_clear(&(*ret)[i]); + } + } + +#if defined (__i386__) || defined (__x86_64__) + if (want_wc && !keep_wc) { +#if defined (__x86_64__) && defined (UEFI) + efi_pt_restore(); +#else + mtrr_restore(); +#endif + } +#else + (void)want_wc; +#endif } void fb_clear(struct fb_info *fb) { @@ -74,31 +115,7 @@ (size_t)fb->framebuffer_pitch * fb->framebuffer_height); } -#if defined (__x86_64__) || defined (__i386__) -static void fb_flush_x86(volatile void *base, size_t length) { - static size_t clsz = 0; - if (clsz == 0) { - uint32_t eax, ebx, ecx, edx; - if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx)) - return; - clsz = ((ebx >> 8) & 0xFF) * 8; - if (clsz == 0) - return; - } - - uintptr_t start = ALIGN_DOWN((uintptr_t)base, clsz); - uintptr_t end = ALIGN_UP((uintptr_t)base + length, clsz, panic(false, "fb: Alignment overflow")); - for (uintptr_t ptr = start; ptr < end; ptr += clsz) { - asm volatile ("clflush (%0)" :: "r"(ptr) : "memory"); - } -} - -static void fb_flush_x86_wbinvd(volatile void *base, size_t length) { - (void)base; - (void)length; - asm volatile ("wbinvd" ::: "memory"); -} -#elif defined (__aarch64__) +#if defined (__aarch64__) static void fb_flush_aarch64(volatile void *base, size_t length) { clean_dcache_poc((uintptr_t)base, (uintptr_t)base + length); } @@ -150,14 +167,7 @@ static flush_fn fn = NULL; if (fn == NULL) { -#if defined (__x86_64__) || defined (__i386__) - uint32_t eax, ebx, ecx, edx; - if (cpuid(1, 0, &eax, &ebx, &ecx, &edx) && ((edx >> 19) & 1)) { - fn = fb_flush_x86; - } else { - fn = fb_flush_x86_wbinvd; - } -#elif defined (__aarch64__) +#if defined (__aarch64__) fn = fb_flush_aarch64; #elif defined (__riscv) if (riscv_check_isa_extension("zicbom", NULL, NULL)) { @@ -170,5 +180,7 @@ #endif } - fn(base, length); + if (fn != NULL) { + fn(base, length); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/fb.h new/limine-12.3.1/common/lib/fb.h --- old/limine-12.2.0/common/lib/fb.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/fb.h 2026-05-24 18:16:54.000000000 +0200 @@ -38,7 +38,7 @@ void fb_init(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp, - bool preserve_screen); + bool preserve_screen, bool keep_wc); void fb_clear(struct fb_info *fb); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/getchar.c new/limine-12.3.1/common/lib/getchar.c --- old/limine-12.2.0/common/lib/getchar.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/getchar.c 2026-05-24 18:16:54.000000000 +0200 @@ -156,12 +156,21 @@ return 0; } -int pit_sleep_and_quit_on_keypress(int seconds) { +int pit_sleep_ms_and_quit_on_keypress(uint64_t milliseconds) { + uint64_t ticks64 = milliseconds > (UINT64_MAX - 999) / 18 + ? UINT64_MAX + : (milliseconds * 18 + 999) / 1000; + uint32_t ticks = ticks64 > UINT32_MAX ? UINT32_MAX : ticks64; + + if (ticks == 0) { + return 0; + } + if (!serial) { - return _pit_sleep_and_quit_on_keypress(seconds * 18); + return _pit_sleep_and_quit_on_keypress(ticks); } - for (int i = 0; i < seconds * 18; i++) { + for (uint32_t i = 0; i < ticks; i++) { int ret = _pit_sleep_and_quit_on_keypress(1); if (ret != 0) { @@ -195,6 +204,10 @@ return 0; } + +int pit_sleep_and_quit_on_keypress(int seconds) { + return pit_sleep_ms_and_quit_on_keypress((uint64_t)seconds * 1000); +} #endif #if defined (UEFI) @@ -254,7 +267,7 @@ return 0; } -int pit_sleep_and_quit_on_keypress(int seconds) { +int pit_sleep_ms_and_quit_on_keypress(uint64_t milliseconds) { EFI_KEY_DATA kd; UINTN which; @@ -287,7 +300,8 @@ restart: gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &events[1]); - gBS->SetTimer(events[1], TimerRelative, (uint64_t)10000000 * seconds); + gBS->SetTimer(events[1], TimerRelative, + milliseconds > UINT64_MAX / 10000 ? UINT64_MAX : milliseconds * 10000); again: memset(&kd, 0, sizeof(EFI_KEY_DATA)); @@ -362,4 +376,8 @@ gBS->CloseEvent(events[1]); return ret; } + +int pit_sleep_and_quit_on_keypress(int seconds) { + return pit_sleep_ms_and_quit_on_keypress((uint64_t)seconds * 1000); +} #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/gterm.c new/limine-12.3.1/common/lib/gterm.c --- old/limine-12.2.0/common/lib/gterm.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/gterm.c 2026-05-24 18:16:54.000000000 +0200 @@ -10,7 +10,6 @@ #include <lib/image.h> #include <lib/rand.h> #include <mm/pmm.h> -#include <mm/mtrr.h> #include <flanterm.h> #include <flanterm_backends/fb.h> #include <lib/term.h> @@ -797,7 +796,7 @@ term_notready(); // We force bpp to 32 - fb_init(&fbs, &fbs_count, width, height, 32, true); + fb_init(&fbs, &fbs_count, width, height, 32, true, true); if (_fbs != NULL) { *_fbs = fbs; @@ -810,19 +809,6 @@ return false; } -#if defined (__i386__) || defined (__x86_64__) - for (size_t i = 0; i < fbs_count; i++) { - if (fbs[i].framebuffer_bpp != 32) { - continue; - } - uint64_t fb_size = (uint64_t)fbs[i].framebuffer_pitch * fbs[i].framebuffer_height; - if (fb_size == 0) { - continue; - } - mtrr_wc_add_fb_range(fbs[i].framebuffer_addr, fb_size); - } -#endif - struct gterm_config cfg; gterm_parse_config(config, &cfg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/misc.h new/limine-12.3.1/common/lib/misc.h --- old/limine-12.2.0/common/lib/misc.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/misc.h 2026-05-24 18:16:54.000000000 +0200 @@ -56,6 +56,7 @@ noreturn void panic(bool allow_menu, const char *fmt, ...); int pit_sleep_and_quit_on_keypress(int seconds); +int pit_sleep_ms_and_quit_on_keypress(uint64_t milliseconds); uint64_t strtoui(const char *s, const char **end, int base); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/term.c new/limine-12.3.1/common/lib/term.c --- old/limine-12.2.0/common/lib/term.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/term.c 2026-05-24 18:16:54.000000000 +0200 @@ -7,6 +7,7 @@ #include <lib/fb.h> #include <mm/pmm.h> #include <mm/mtrr.h> +#include <mm/efi_pt.h> #include <drivers/vga_textmode.h> #include <flanterm_backends/fb.h> @@ -21,7 +22,11 @@ void term_notready(void) { #if defined (__i386__) || defined (__x86_64__) - mtrr_wc_clear_fb_ranges(); +#if defined (__x86_64__) && defined (UEFI) + efi_pt_restore(); +#else + mtrr_restore(); +#endif #endif for (size_t i = 0; i < terms_i; i++) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/lib/term.h new/limine-12.3.1/common/lib/term.h --- old/limine-12.2.0/common/lib/term.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/lib/term.h 2026-05-24 18:16:54.000000000 +0200 @@ -3,6 +3,7 @@ #include <stddef.h> #include <stdint.h> +#include <stdbool.h> #include <lib/print.h> #include <flanterm.h> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/menu.c new/limine-12.3.1/common/menu.c --- old/limine-12.2.0/common/menu.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/menu.c 2026-05-24 18:16:54.000000000 +0200 @@ -40,6 +40,7 @@ #define TOK_VALUE 2 #define TOK_BADKEY 3 #define TOK_COMMENT 4 +#define TIMEOUT_MAX_MS (UINT64_C(9999) * 1000) static char interface_help_colour[24] = "\e[38;2;0;170;0m"; static char interface_help_colour_bright[24] = "\e[38;2;85;255;85m"; @@ -47,6 +48,22 @@ static char *menu_branding = NULL; +static char *append_uint_dec(char *p, uint64_t val) { + char buf[20]; + size_t i = 0; + + do { + buf[i++] = '0' + (val % 10); + val /= 10; + } while (val != 0); + + while (i != 0) { + *p++ = buf[--i]; + } + *p = '\0'; + return p; +} + static char *write_uint8_dec(char *p, uint8_t v) { if (v >= 100) { *p++ = '0' + v / 100; @@ -61,6 +78,73 @@ return p; } +static uint64_t parse_timeout_ms(const char *str) { + uint64_t seconds = 0; + uint64_t milliseconds = 0; + bool any = false; + + while (isdigit(*str)) { + any = true; + if (seconds <= TIMEOUT_MAX_MS / 1000) { + seconds *= 10; + seconds += *str - '0'; + } + str++; + } + + if (*str == '.') { + uint64_t multiplier = 100; + + str++; + + while (isdigit(*str)) { + any = true; + + if (multiplier != 0) { + milliseconds += (*str - '0') * multiplier; + multiplier /= 10; + } else if (*str != '0' && milliseconds < 999) { + milliseconds++; + } + + str++; + } + } + + if (!any) { + return 0; + } + + if (seconds > TIMEOUT_MAX_MS / 1000) { + return UINT64_MAX; + } + + return seconds * 1000 + milliseconds; +} + +static size_t format_timeout_ms(char *buf, uint64_t milliseconds) { + char *p = append_uint_dec(buf, milliseconds / 1000); + uint64_t subsecond = milliseconds % 1000; + + if (subsecond != 0) { + char *last; + + *p++ = '.'; + *p++ = '0' + subsecond / 100; + *p++ = '0' + (subsecond / 10) % 10; + *p++ = '0' + subsecond % 10; + + last = p - 1; + while (*last == '0') { + last--; + } + p = last + 1; + } + + *p = '\0'; + return p - buf; +} + static void format_fg_rgb_escape(char *buf, uint32_t rgb) { char *p = buf; *p++ = '\e'; *p++ = '['; *p++ = '3'; *p++ = '8'; *p++ = ';'; @@ -1113,22 +1197,6 @@ return p; } -static char *append_uint_dec(char *p, uint64_t val) { - char buf[20]; - size_t i = 0; - - do { - buf[i++] = '0' + (val % 10); - val /= 10; - } while (val != 0); - - while (i != 0) { - *p++ = buf[--i]; - } - *p = '\0'; - return p; -} - static const char *uefi_shell_filename(void) { #if defined (__x86_64__) return "shellx64.efi"; @@ -1559,11 +1627,15 @@ } size_t timeout = 5; + uint64_t timeout_ms = timeout * 1000; bool has_timeout = false; #if defined (UEFI) has_timeout = bli_update_oneshot_timeout(&timeout, &skip_timeout); + if (has_timeout) { + timeout_ms = (uint64_t)timeout * 1000; + } #endif if (!has_timeout) { @@ -1573,18 +1645,19 @@ if (!strcmp(timeout_config, "no")) skip_timeout = true; else - timeout = strtoui(timeout_config, NULL, 10); + timeout_ms = parse_timeout_ms(timeout_config); } } #if defined (UEFI) if (!has_timeout) { has_timeout = bli_update_timeout(&timeout, &skip_timeout); + timeout_ms = (uint64_t)timeout * 1000; } #endif - if (timeout > 9999) - timeout = 9999; + if (timeout_ms > TIMEOUT_MAX_MS) + timeout_ms = TIMEOUT_MAX_MS; #if defined(UEFI) bool reboot_to_firmware_supported = reboot_to_fw_ui_supported(); @@ -1596,7 +1669,7 @@ skip_timeout = true; } - if (!skip_timeout && !timeout) { + if (!skip_timeout && !timeout_ms) { if (max_entries == 0 || selected_menu_entry == NULL || selected_menu_entry->sub != NULL) { quiet = false; print("Default entry is not valid or directory, booting to menu.\n"); @@ -1757,17 +1830,23 @@ if (skip_timeout == false) { print("\n\n"); - for (size_t i = timeout; i; i--) { - size_t ndigits = 1; - for (size_t tmp = i / 10; tmp > 0; tmp /= 10) ndigits++; - size_t msg_len = 28 + ndigits; + while (timeout_ms != 0) { + char timeout_buf[24]; + uint64_t sleep_ms = timeout_ms % 1000; + size_t timeout_len = format_timeout_ms(timeout_buf, timeout_ms); + size_t msg_len = 28 + timeout_len; set_cursor_pos_helper((terms[0]->cols - msg_len) / 2, terms[0]->rows - 2); FOR_TERM(TERM->scroll_enabled = false); - print("\e[2K%sBooting automatically in %s%U%s...\e[0m", - interface_help_colour, interface_help_colour_bright, (uint64_t)i, interface_help_colour); + print("\e[2K%sBooting automatically in %s%s%s...\e[0m", + interface_help_colour, interface_help_colour_bright, timeout_buf, interface_help_colour); FOR_TERM(TERM->scroll_enabled = true); FOR_TERM(TERM->double_buffer_flush(TERM)); - if ((c = pit_sleep_and_quit_on_keypress(1))) { + + if (sleep_ms == 0) { + sleep_ms = 1000; + } + + if ((c = pit_sleep_ms_and_quit_on_keypress(sleep_ms))) { skip_timeout = true; if (quiet) { quiet = false; @@ -1778,6 +1857,7 @@ FOR_TERM(TERM->double_buffer_flush(TERM)); goto timeout_aborted; } + timeout_ms -= sleep_ms; } goto autoboot; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/mm/efi_pt.c new/limine-12.3.1/common/mm/efi_pt.c --- old/limine-12.2.0/common/mm/efi_pt.c 1970-01-01 01:00:00.000000000 +0100 +++ new/limine-12.3.1/common/mm/efi_pt.c 2026-05-24 18:16:54.000000000 +0200 @@ -0,0 +1,358 @@ +#if defined (__x86_64__) && defined (UEFI) + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <mm/efi_pt.h> +#include <mm/pmm.h> +#include <sys/cpu.h> + +#define PTE_P ((uint64_t)1 << 0) +#define PTE_RW ((uint64_t)1 << 1) +#define PTE_US ((uint64_t)1 << 2) +#define PTE_PWT ((uint64_t)1 << 3) +#define PTE_PCD ((uint64_t)1 << 4) +#define PTE_PS ((uint64_t)1 << 7) +#define PTE_PAT_4K ((uint64_t)1 << 7) +#define PTE_PAT_BIG ((uint64_t)1 << 12) +#define PTE_NX ((uint64_t)1 << 63) +#define PT_ADDR_MASK ((uint64_t)0x000FFFFFFFFFF000) + +#define IA32_PAT_MSR 0x277 +#define PAT_TYPE_WC 0x01 + +static bool la57_enabled(void) { + uint64_t cr4; + asm volatile ("mov %%cr4, %0" : "=r"(cr4)); + return !!(cr4 & ((uint64_t)1 << 12)); +} + +static bool gib_pages_supported(void) { + uint32_t eax, ebx, ecx, edx; + return cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx) && !!(edx & (1 << 26)); +} + +// Firmware PTEs we overwrote, replayed by efi_pt_restore() to undo the FB WC. +// On overflow we stop applying WC so the undo stays complete. +#define SAVED_PTES_MAX 1024 + +static uint64_t **saved_pte_ptr = NULL; +static uint64_t *saved_pte_val = NULL; +static size_t saved_pte_i = 0; +static uint64_t saved_pat = 0; +static bool pat_modified = false; + +static int wc_pat_index = -1; +static bool gib_supported = false; + +static bool save_pte(uint64_t *slot) { + if (saved_pte_i >= SAVED_PTES_MAX) { + return false; + } + saved_pte_ptr[saved_pte_i] = slot; + saved_pte_val[saved_pte_i] = *slot; + saved_pte_i++; + return true; +} + +// Caches off + TLB flushed for a safe PAT-MSR memory-type change. +static void cache_off(uint64_t *old_cr0) { + asm volatile ("mov %%cr0, %0" : "=r"(*old_cr0) :: "memory"); + asm volatile ("mov %0, %%cr0" + :: "r"((*old_cr0 | ((uint64_t)1 << 30)) & ~((uint64_t)1 << 29)) + : "memory"); + asm volatile ("wbinvd" ::: "memory"); + uint64_t cr3; + asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory"); + asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory"); +} + +static void cache_on(uint64_t old_cr0) { + uint64_t cr3; + asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory"); + asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory"); + asm volatile ("wbinvd" ::: "memory"); + asm volatile ("mov %0, %%cr0" :: "r"(old_cr0) : "memory"); +} + +// WP off to write read-only firmware PTEs; wp_on flushes the TLB to apply them. +static void wp_off(uint64_t *old_cr0) { + asm volatile ("mov %%cr0, %0" : "=r"(*old_cr0) :: "memory"); + asm volatile ("mov %0, %%cr0" :: "r"(*old_cr0 & ~((uint64_t)1 << 16)) : "memory"); +} + +static void wp_on(uint64_t old_cr0) { + // A plain CR3 reload leaves global TLB entries intact, so a firmware FB + // mapped with the global bit would keep its old memory type. Toggling + // CR4.PGE flushes the whole TLB including global entries (Intel SDM + // 4.10.4.1); fall back to a CR3 reload when PGE is off (no globals exist). + uint64_t cr4; + asm volatile ("mov %%cr4, %0" : "=r"(cr4) :: "memory"); + if (cr4 & ((uint64_t)1 << 7)) { + asm volatile ("mov %0, %%cr4" :: "r"(cr4 & ~((uint64_t)1 << 7)) : "memory"); + asm volatile ("mov %0, %%cr4" :: "r"(cr4) : "memory"); + } else { + uint64_t cr3; + asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory"); + asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory"); + } + asm volatile ("mov %0, %%cr0" :: "r"(old_cr0) : "memory"); +} + +static int pte_pat_index(uint64_t e, bool leaf4k) { + uint64_t patbit = leaf4k ? PTE_PAT_4K : PTE_PAT_BIG; + return (!!(e & patbit) << 2) | (!!(e & PTE_PCD) << 1) | !!(e & PTE_PWT); +} + +// Non-leaf entries and CR3 have no PAT bit: typed by PCD/PWT only. +static int walk_pat_index(uint64_t e) { + return (!!(e & PTE_PCD) << 1) | !!(e & PTE_PWT); +} + +static void scan_walk(uint64_t *table, int lvl, uint8_t *used) { + for (size_t i = 0; i < 512; i++) { + if (*used == 0xff) { + return; + } + uint64_t e = table[i]; + if (!(e & PTE_P)) { + continue; + } + if ((lvl == 1) || (lvl <= 3 && (e & PTE_PS))) { + *used |= 1 << pte_pat_index(e, lvl == 1); + } else { + *used |= 1 << walk_pat_index(e); + scan_walk((uint64_t *)(e & PT_ADDR_MASK), lvl - 1, used); + } + } +} + +static uint8_t scan_used_pat_indices(void) { + uint64_t cr3; + asm volatile ("mov %%cr3, %0" : "=r"(cr3)); + uint8_t used = 1 << walk_pat_index(cr3); + scan_walk((uint64_t *)(cr3 & PT_ADDR_MASK), la57_enabled() ? 5 : 4, &used); + return used; +} + +// Reuse a WC slot if present, else repurpose one no live mapping selects. +static bool ensure_wc_pat_slot(void) { + if (wc_pat_index >= 0) { + return true; + } + + uint32_t eax, ebx, ecx, edx; + if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx) || !(edx & (1 << 16))) { + return false; + } + + uint64_t pat = rdmsr(IA32_PAT_MSR); + + for (int i = 0; i < 8; i++) { + if (((pat >> (i * 8)) & 0xff) == PAT_TYPE_WC) { + wc_pat_index = i; + return true; + } + } + + uint8_t used = scan_used_pat_indices(); + + int slot = -1; + for (int i = 4; i < 8; i++) { + if (!(used & (1 << i))) { + slot = i; + break; + } + } + if (slot < 0) { + for (int i = 0; i < 4; i++) { + if (!(used & (1 << i))) { + slot = i; + break; + } + } + } + if (slot < 0) { + return false; + } + + saved_pat = pat; + pat_modified = true; + + pat = (pat & ~((uint64_t)0xff << (slot * 8))) + | ((uint64_t)PAT_TYPE_WC << (slot * 8)); + + uint64_t old_cr0; + cache_off(&old_cr0); + wrmsr(IA32_PAT_MSR, pat); + cache_on(old_cr0); + + wc_pat_index = slot; + return true; +} + +static uint64_t pte_set_pat(uint64_t e, int idx, bool leaf4k) { + uint64_t patbit = leaf4k ? PTE_PAT_4K : PTE_PAT_BIG; + e &= ~(PTE_PWT | PTE_PCD | patbit); + if (idx & 1) e |= PTE_PWT; + if (idx & 2) e |= PTE_PCD; + if (idx & 4) e |= patbit; + return e; +} + +// Children inherit the parent mapping so memory sharing the leaf keeps its type. +static uint64_t *split_leaf(uint64_t e, int lvl) { + uint64_t leaf_sz = (uint64_t)1 << ((lvl - 1) * 9 + 12); + uint64_t phys_base = e & PT_ADDR_MASK & ~(leaf_sz - 1); + int idx = pte_pat_index(e, false); + uint64_t flags = e & (PTE_P | PTE_RW | PTE_US | PTE_NX); + + int child_lvl = lvl - 1; + uint64_t child_sz = (uint64_t)1 << ((child_lvl - 1) * 9 + 12); + bool child_4k = child_lvl == 1; + + uint64_t *t = ext_mem_alloc(0x1000); + for (int i = 0; i < 512; i++) { + uint64_t c = (phys_base + (uint64_t)i * child_sz) | flags; + if (!child_4k) { + c |= PTE_PS; + } + t[i] = pte_set_pat(c, idx, child_4k); + } + return t; +} + +// pristine: inside firmware tables (saved); tables we allocate are not. +static void wc_walk(uint64_t *table, int lvl, uint64_t tbl_va, + uint64_t base, uint64_t end, bool pristine) { + uint64_t step = (uint64_t)1 << ((lvl - 1) * 9 + 12); + + for (size_t i = 0; i < 512; i++) { + uint64_t va = tbl_va + (uint64_t)i * step; + if (va >= end) { + break; + } + if (va + step <= base) { + continue; + } + + uint64_t *e = &table[i]; + bool present = !!(*e & PTE_P); + bool is_leaf = (lvl == 1) || (present && lvl <= 3 && (*e & PTE_PS)); + bool fully = va >= base && va + step <= end; + + if (fully && lvl <= 3 && (lvl < 3 || gib_supported)) { + uint64_t leaf; + if (present && is_leaf) { + leaf = (*e & PT_ADDR_MASK & ~(step - 1)) + | (*e & (PTE_P | PTE_RW | PTE_US | PTE_NX)); + } else { + leaf = va | PTE_P | PTE_RW; + } + if (lvl >= 2) { + leaf |= PTE_PS; + } + if (pristine && !save_pte(e)) { + continue; + } + *e = pte_set_pat(leaf, wc_pat_index, lvl == 1); + continue; + } + + if (present && !is_leaf) { + wc_walk((uint64_t *)(*e & PT_ADDR_MASK), lvl - 1, va, + base, end, pristine); + continue; + } + + if (pristine && !save_pte(e)) { + continue; + } + uint64_t *child; + if (present) { + child = split_leaf(*e, lvl); + } else { + child = ext_mem_alloc(0x1000); + } + *e = (uint64_t)child | PTE_P | PTE_RW | PTE_US; + wc_walk(child, lvl - 1, va, base, end, false); + } +} + +void efi_pt_set_fb_wc(uint64_t base, uint64_t size) { + if (size == 0) { + return; + } + + if (saved_pte_ptr == NULL) { + saved_pte_ptr = ext_mem_alloc(SAVED_PTES_MAX * sizeof(uint64_t *)); + saved_pte_val = ext_mem_alloc(SAVED_PTES_MAX * sizeof(uint64_t)); + } + + bool ints = disable_interrupts(); + + if (!ensure_wc_pat_slot()) { + goto out; + } + + uint64_t end = (base + size + 0xfff) & ~(uint64_t)0xfff; + base &= ~(uint64_t)0xfff; + + uint64_t cr3; + asm volatile ("mov %%cr3, %0" : "=r"(cr3)); + uint64_t *top = (uint64_t *)(cr3 & PT_ADDR_MASK); + int levels = la57_enabled() ? 5 : 4; + gib_supported = gib_pages_supported(); + + uint64_t old_cr0; + wp_off(&old_cr0); + wc_walk(top, levels, 0, base, end, true); + wp_on(old_cr0); + +out: + if (ints) { + enable_interrupts(); + } +} + +void efi_pt_restore(void) { + if (saved_pte_i == 0 && !pat_modified) { + goto out; + } + + bool ints = disable_interrupts(); + + if (saved_pte_i != 0) { + uint64_t old_cr0; + wp_off(&old_cr0); + for (size_t i = saved_pte_i; i-- > 0;) { + *saved_pte_ptr[i] = saved_pte_val[i]; + } + wp_on(old_cr0); + } + + if (pat_modified) { + uint64_t old_cr0; + cache_off(&old_cr0); + wrmsr(IA32_PAT_MSR, saved_pat); + cache_on(old_cr0); + } + + if (ints) { + enable_interrupts(); + } + + saved_pte_i = 0; + pat_modified = false; + wc_pat_index = -1; + +out: + if (saved_pte_ptr != NULL) { + pmm_free(saved_pte_ptr, SAVED_PTES_MAX * sizeof(uint64_t *)); + pmm_free(saved_pte_val, SAVED_PTES_MAX * sizeof(uint64_t)); + saved_pte_ptr = NULL; + saved_pte_val = NULL; + } +} + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/mm/efi_pt.h new/limine-12.3.1/common/mm/efi_pt.h --- old/limine-12.2.0/common/mm/efi_pt.h 1970-01-01 01:00:00.000000000 +0100 +++ new/limine-12.3.1/common/mm/efi_pt.h 2026-05-24 18:16:54.000000000 +0200 @@ -0,0 +1,13 @@ +#ifndef MM__EFI_PT_H__ +#define MM__EFI_PT_H__ + +#include <stdint.h> + +#if defined (__x86_64__) && defined (UEFI) + +void efi_pt_set_fb_wc(uint64_t base, uint64_t size); +void efi_pt_restore(void); + +#endif + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/mm/mtrr.c new/limine-12.3.1/common/mm/mtrr.c --- old/limine-12.2.0/common/mm/mtrr.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/mm/mtrr.c 2026-05-24 18:16:54.000000000 +0200 @@ -20,22 +20,25 @@ uint64_t *saved_mtrrs = NULL; void mtrr_save(void) { + if (saved_mtrrs != NULL) { + return; + } if (!mtrr_supported()) { return; } + bool ints = disable_interrupts(); + uint64_t ia32_mtrrcap = rdmsr(0xfe); uint8_t var_reg_count = ia32_mtrrcap & 0xff; bool fix_supported = !!(ia32_mtrrcap & ((uint64_t)1 << 8)); - if (saved_mtrrs == NULL) { - saved_mtrrs = ext_mem_alloc(( - (var_reg_count * 2) /* variable MTRRs, 2 MSRs each */ - + 11 /* 11 fixed MTRRs */ - + 1 /* 1 default type MTRR */ - ) * sizeof(uint64_t)); - } + saved_mtrrs = ext_mem_alloc(( + (var_reg_count * 2) /* variable MTRRs, 2 MSRs each */ + + 11 /* 11 fixed MTRRs */ + + 1 /* 1 default type MTRR */ + ) * sizeof(uint64_t)); /* save variable range MTRRs */ for (uint8_t i = 0; i < var_reg_count * 2; i += 2) { @@ -63,6 +66,10 @@ /* make sure that the saved MTRR default has MTRRs off */ saved_mtrrs[var_reg_count * 2 + 11] &= ~((uint64_t)1 << 11); + + if (ints) { + enable_interrupts(); + } } void mtrr_restore(void) { @@ -76,9 +83,11 @@ bool fix_supported = !!(ia32_mtrrcap & ((uint64_t)1 << 8)); if (saved_mtrrs == NULL) { - panic(true, "mtrr: Attempted restore without prior save"); + return; } + bool ints = disable_interrupts(); + /* according to the Intel SDM 12.11.7.2 "MemTypeSet() Function", we need to follow this procedure before changing MTRR set up */ @@ -141,25 +150,52 @@ /* restore old value of cr0 */ asm volatile ("mov %0, %%cr0" :: "r"(old_cr0) : "memory"); + + if (ints) { + enable_interrupts(); + } } #define MTRR_TYPE_WC 1 -#define WC_MAX_SLOTS 4 -static struct { - uint8_t slot; - uint64_t saved_base; - uint64_t saved_mask; -} wc_saved[WC_MAX_SLOTS]; -static size_t wc_n_saved = 0; +static bool wc_add_mtrr(uint64_t base, uint64_t size, uint8_t type, + uint8_t maxphysaddr, uint8_t var_reg_count) { + uint8_t slot = 0xff; + for (uint8_t i = 0; i < var_reg_count; i++) { + if (!(rdmsr(0x200 + i * 2 + 1) & ((uint64_t)1 << 11))) { + slot = i; + break; + } + } + if (slot == 0xff) { + return false; + } + uint64_t mask = (((uint64_t)1 << maxphysaddr) - 1) & ~(size - 1); + wrmsr(0x200 + slot * 2, base | type); + wrmsr(0x200 + slot * 2 + 1, mask | ((uint64_t)1 << 11)); + return true; +} + +static bool wc_add_chunks(uint64_t base, uint64_t span, uint8_t type, + uint8_t maxphysaddr, uint8_t var_reg_count) { + while (span > 0) { + uint64_t align_k = base != 0 ? ((uint64_t)1 << __builtin_ctzll(base)) : span; + uint64_t size_k = (uint64_t)1 << (63 - __builtin_clzll(span)); + uint64_t k = align_k < size_k ? align_k : size_k; + + if (!wc_add_mtrr(base, k, type, maxphysaddr, var_reg_count)) { + return false; + } + base += k; + span -= k; + } + return true; +} bool mtrr_wc_add_fb_range(uint64_t base, uint64_t size) { if (size == 0 || !mtrr_supported()) { return false; } - if (wc_n_saved >= WC_MAX_SLOTS) { - return false; - } uint64_t mtrrcap = rdmsr(0xfe); if (!(mtrrcap & ((uint64_t)1 << 10))) { @@ -176,23 +212,9 @@ return false; } + uint64_t end = (base + size + 0xfff) & ~(uint64_t)0xfff; base &= ~(uint64_t)0xfff; - - uint64_t aligned_size = 0x1000; - while (aligned_size < size) { - aligned_size <<= 1; - if (aligned_size == 0) { - return false; - } - } - size = aligned_size; - - // MTRR match is (addr & mask) == (base & mask); only correct when base is size-aligned. - if (base & (size - 1)) { - return false; - } - - uint64_t mask = (((uint64_t)1 << maxphysaddr) - 1) & ~(size - 1); + size = end - base; for (uint8_t i = 0; i < var_reg_count; i++) { uint64_t mb = rdmsr(0x200 + i * 2); @@ -202,74 +224,14 @@ } uint64_t exist_mask = mm & ~(uint64_t)0xfff; uint64_t exist_base = mb & ~(uint64_t)0xfff; - for (uint64_t a = base; a < base + size; a += 0x1000) { + for (uint64_t a = base; a < end; a += 0x1000) { if ((a & exist_mask) == (exist_base & exist_mask)) { return false; } } } - uint8_t slot; - bool found = false; - for (uint8_t i = 0; i < var_reg_count; i++) { - uint64_t mm = rdmsr(0x200 + i * 2 + 1); - if (!(mm & ((uint64_t)1 << 11))) { - slot = i; - found = true; - break; - } - } - if (!found) { - return false; - } - -#if defined (UEFI) - asm volatile ("cli"); -#endif - - uintptr_t old_cr0; - asm volatile ("mov %%cr0, %0" : "=r"(old_cr0) :: "memory"); - uintptr_t new_cr0 = (old_cr0 | (1U << 30)) & ~((uintptr_t)1 << 29); - asm volatile ("mov %0, %%cr0" :: "r"(new_cr0) : "memory"); - asm volatile ("wbinvd" ::: "memory"); - - uintptr_t cr3; - asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory"); - asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory"); - - uint64_t mtrr_def = rdmsr(0x2ff); - wrmsr(0x2ff, mtrr_def & ~((uint64_t)1 << 11)); - - wc_saved[wc_n_saved].slot = slot; - wc_saved[wc_n_saved].saved_base = rdmsr(0x200 + slot * 2); - wc_saved[wc_n_saved].saved_mask = rdmsr(0x200 + slot * 2 + 1); - wc_n_saved++; - - wrmsr(0x200 + slot * 2, base | MTRR_TYPE_WC); - wrmsr(0x200 + slot * 2 + 1, mask | ((uint64_t)1 << 11)); - - wrmsr(0x2ff, mtrr_def | ((uint64_t)1 << 11)); - - asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory"); - asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory"); - asm volatile ("wbinvd" ::: "memory"); - asm volatile ("mov %0, %%cr0" :: "r"(old_cr0) : "memory"); - -#if defined (UEFI) - asm volatile ("sti"); -#endif - - return true; -} - -void mtrr_wc_clear_fb_ranges(void) { - if (wc_n_saved == 0) { - return; - } - if (!mtrr_supported()) { - wc_n_saved = 0; - return; - } + mtrr_save(); #if defined (UEFI) asm volatile ("cli"); @@ -288,10 +250,7 @@ uint64_t mtrr_def = rdmsr(0x2ff); wrmsr(0x2ff, mtrr_def & ~((uint64_t)1 << 11)); - for (size_t i = 0; i < wc_n_saved; i++) { - wrmsr(0x200 + wc_saved[i].slot * 2, wc_saved[i].saved_base); - wrmsr(0x200 + wc_saved[i].slot * 2 + 1, wc_saved[i].saved_mask); - } + bool ok = wc_add_chunks(base, size, MTRR_TYPE_WC, maxphysaddr, var_reg_count); wrmsr(0x2ff, mtrr_def); @@ -304,7 +263,7 @@ asm volatile ("sti"); #endif - wc_n_saved = 0; + return ok; } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/mm/mtrr.h new/limine-12.3.1/common/mm/mtrr.h --- old/limine-12.2.0/common/mm/mtrr.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/mm/mtrr.h 2026-05-24 18:16:54.000000000 +0200 @@ -10,7 +10,6 @@ void mtrr_restore(void); bool mtrr_wc_add_fb_range(uint64_t base, uint64_t size); -void mtrr_wc_clear_fb_ranges(void); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/chainload.c new/limine-12.3.1/common/protos/chainload.c --- old/limine-12.2.0/common/protos/chainload.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/chainload.c 2026-05-24 18:16:54.000000000 +0200 @@ -305,7 +305,7 @@ struct fb_info *fbinfo; size_t fb_count; - fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp, false); + fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp, false, false); size_t cmdline_len = strlen(cmdline); CHAR16 *new_cmdline; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/limine.c new/limine-12.3.1/common/protos/limine.c --- old/limine-12.2.0/common/protos/limine.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/limine.c 2026-05-24 18:16:54.000000000 +0200 @@ -1374,10 +1374,11 @@ struct fb_info *fbs; size_t fbs_count; + bool preserve_screen = get_request(LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID) != NULL; + term_notready(); - bool preserve_screen = get_request(LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID) != NULL; - fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, preserve_screen); + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, preserve_screen, false); if (fbs_count == 0) { goto no_fb; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/linux_risc.c new/limine-12.3.1/common/protos/linux_risc.c --- old/limine-12.2.0/common/protos/linux_risc.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/linux_risc.c 2026-05-24 18:16:54.000000000 +0200 @@ -277,7 +277,7 @@ term_notready(); - fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false); + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false); // TODO(qookie): Let the user pick a framebuffer if there's > 1 if (fbs_count > 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/linux_x86.c new/limine-12.3.1/common/protos/linux_x86.c --- old/limine-12.2.0/common/protos/linux_x86.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/linux_x86.c 2026-05-24 18:16:54.000000000 +0200 @@ -407,13 +407,30 @@ if (setup_header->version >= 0x205 && setup_header->kernel_alignment > kernel_align) { kernel_align = setup_header->kernel_alignment; } - uintptr_t kernel_load_addr = ALIGN_UP(0x100000, kernel_align, panic(true, "linux: Alignment overflow")); + // Start at pref_address: the decompressor relocates itself up to + // LOAD_PHYSICAL_ADDR (= pref_address) and scribbles init_size bytes from + // there, so loading below it would leave that range unreserved. + uintptr_t kernel_search_start = 0x100000; + if (setup_header->version >= 0x20a + && setup_header->pref_address >= 0x100000 + && setup_header->pref_address + (uint64_t)kernel_alloc_size <= UINTPTR_MAX) { + kernel_search_start = (uintptr_t)setup_header->pref_address; + } + // Non-relocatable kernels must be loaded at their required address; do + // not step up on failure. + bool relocatable_kernel = setup_header->version >= 0x205 + && setup_header->relocatable_kernel != 0; + uintptr_t kernel_load_addr = ALIGN_UP(kernel_search_start, kernel_align, panic(true, "linux: Alignment overflow")); for (;;) { if (memmap_alloc_range(kernel_load_addr, ALIGN_UP(kernel_alloc_size, 4096, panic(true, "linux: Alignment overflow")), MEMMAP_BOOTLOADER_RECLAIMABLE, MEMMAP_USABLE, false, false, false)) break; + if (!relocatable_kernel) { + panic(true, "linux: Non-relocatable kernel could not be loaded at required address %X", (uint64_t)kernel_load_addr); + } + if (kernel_load_addr >= 0xfff00000) { panic(true, "linux: Failed to allocate memory for kernel"); } @@ -569,7 +586,7 @@ #if defined (UEFI) gop_force_16 = true; #endif - fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false); + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false); if (fbs_count == 0) { #if defined (UEFI) goto no_fb; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/multiboot1.c new/limine-12.3.1/common/protos/multiboot1.c --- old/limine-12.2.0/common/protos/multiboot1.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/multiboot1.c 2026-05-24 18:16:54.000000000 +0200 @@ -436,7 +436,7 @@ struct fb_info *fbs; size_t fbs_count; - fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false); + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false); if (fbs_count == 0) { #if defined (UEFI) goto skip_modeset; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/protos/multiboot2.c new/limine-12.3.1/common/protos/multiboot2.c --- old/limine-12.2.0/common/protos/multiboot2.c 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/protos/multiboot2.c 2026-05-24 18:16:54.000000000 +0200 @@ -786,7 +786,7 @@ struct fb_info *fbs; size_t fbs_count; - fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false); + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false); if (fbs_count == 0) { #if defined (BIOS) textmode: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/common/sys/cpu.h new/limine-12.3.1/common/sys/cpu.h --- old/limine-12.2.0/common/sys/cpu.h 2026-05-07 22:33:31.000000000 +0200 +++ new/limine-12.3.1/common/sys/cpu.h 2026-05-24 18:16:54.000000000 +0200 @@ -154,6 +154,32 @@ : "memory"); } +static inline bool disable_interrupts(void) { + uintptr_t flags; + asm volatile ( + "pushf\n\t" + "pop %0\n\t" + "cli\n\t" + : "=r" (flags) + : + : "memory" + ); + return !!(flags & ((uintptr_t)1 << 9)); +} + +static inline bool enable_interrupts(void) { + uintptr_t flags; + asm volatile ( + "pushf\n\t" + "pop %0\n\t" + "sti\n\t" + : "=r" (flags) + : + : "memory" + ); + return !!(flags & ((uintptr_t)1 << 9)); +} + static inline uint64_t rdtsc(void) { uint32_t edx, eax; asm volatile ("rdtsc" : "=a" (eax), "=d" (edx) :: "memory"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/configure new/limine-12.3.1/configure --- old/limine-12.2.0/configure 2026-05-07 22:33:36.000000000 +0200 +++ new/limine-12.3.1/configure 2026-05-24 18:16:58.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.2.0. +# Generated by GNU Autoconf 2.73 for Limine 12.3.1. # # 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.2.0' -PACKAGE_STRING='Limine 12.2.0' +PACKAGE_VERSION='12.3.1' +PACKAGE_STRING='Limine 12.3.1' 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.2.0 to adapt to many kinds of systems. +'configure' configures Limine 12.3.1 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.2.0:";; + short | recursive ) echo "Configuration of Limine 12.3.1:";; 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.2.0 +Limine configure 12.3.1 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.2.0, which was +It was created by Limine $as_me 12.3.1, 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.2.0, which was +This file was extended by Limine $as_me 12.3.1, 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.2.0 +Limine config.status 12.3.1 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.2.0/timestamps new/limine-12.3.1/timestamps --- old/limine-12.2.0/timestamps 2026-05-07 22:33:34.000000000 +0200 +++ new/limine-12.3.1/timestamps 2026-05-24 18:16:55.000000000 +0200 @@ -1,3 +1,3 @@ REGEN_DATE="May 2026" -SOURCE_DATE_EPOCH="1778185588" -SOURCE_DATE_EPOCH_TOUCH="202605072226" +SOURCE_DATE_EPOCH="1779638932" +SOURCE_DATE_EPOCH_TOUCH="202605241808" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/limine-12.2.0/version new/limine-12.3.1/version --- old/limine-12.2.0/version 2026-05-07 22:33:36.000000000 +0200 +++ new/limine-12.3.1/version 2026-05-24 18:16:58.000000000 +0200 @@ -1 +1 @@ -12.2.0 +12.3.1
