Closed phip1611 closed 3 months ago
I run Limine with VERBOSE=yes, but all it tells me is:
multiboot2: Loading kernel `boot:///kernel`...
acpi: Found SMBIOS 32-bit entry point at 0x753f000
acpi: Found SMBIOS 64-bit entry point at 0x753d000
According to the boot information, the boot services are already excited (the boot services not exited tag is not present), an efi_std64 tag is present, and an efi_ih32 tag (bugfix PR open) is present.
Hi, I just tested this, it seems fine to me, booting a test kernel written in C.
Okay, thanks!
I'll do more experiments, including a hand-off without exited boot services, more logging in Limine etc, and come back to you. Likely within the next 4 days.
Alright, mind you though that Limine does not support hand-off without exited boot services (sort of by design, because it is a useless, rarely used mode of multiboot2).
Ah, oh really? GRUB supports it as well. However, GRUB doesn't support some Multiboot-scenarios that Limine supports on the other hand. 🤷🏻
GRUB2 is supposed to be the reference implementation... (let's ignore the places where IT IS the spec and the spec is useless)
From my testing, it is hard to get output from Limine. Perhaps I'm missing something. I use the serial output and capture everything in a file with QEMU.
My observations:
term_notready();
in multiboot2.c
is called, all following print()
are ignoredserial.txt
file, there are never more than 23 lines. This is very oddserial.txt
file is full of ANSI escape sequences - perhaps the problem is rooted there somehowTL;DR: Getting output is hard. And tips?
--
By using the following patch to print the EFI memory map that Limine sees:
print()
(see above)print()
from within liminediff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index e5f085f6..2e7d13a6 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -558,6 +558,49 @@ reloc_fail:
append_tag(info_idx, module_tag);
}
+ //////////////////////////////////////////////
+ // Create EFI memory map tag
+ //////////////////////////////////////////////
+#if defined (UEFI)
+ {
+ if ((efi_mmap_size / efi_desc_size) > MEMMAP_MAX) {
+ panic(false, "multiboot2: too many EFI memory map entries");
+ }
+ if (efi_mmap_size % efi_desc_size != 0) {
+ panic(false, "multiboot2: invalid EFI memory map size");
+ }
+
+ // Create the EFI memory map tag.
+ uint32_t size = sizeof(struct multiboot_tag_efi_mmap) + efi_mmap_size;
+ struct multiboot_tag_efi_mmap *mmap_tag = (struct multiboot_tag_efi_mmap *)(mb2_info + info_idx);
+
+ mmap_tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
+ mmap_tag->descr_vers = efi_desc_ver;
+ mmap_tag->descr_size = efi_desc_size;
+ mmap_tag->size = size;
+
+ print("multiboot2: efi_mmap: \n");
+
+ // Copy over the EFI memory map.
+ memcpy(mmap_tag->efi_mmap, efi_mmap, efi_mmap_size);
+ append_tag(info_idx, mmap_tag);
+
+ print("UEFI memory map: \n");
+ print(" <#> <phys> <size> <type> <attr>\n");
+ int n_entries = efi_mmap_size / efi_desc_size;
+ print("number of entries = %d\n", n_entries);
+ print("tag size = %x\n", size);
+ print("efi memory map size = %x\n", efi_mmap_size);
+
+ // Limine serial log output is weird. In the serial.txt file, there
+ // are never printed more than
+ for (int i = 0; i < n_entries; i++) {
+ EFI_MEMORY_DESCRIPTOR * e = ((char *) efi_mmap) + i * efi_desc_size;
+ print(" [%d] %x %x %x %x: \n", i, e->PhysicalStart, e->NumberOfPages * 4096, e->Type, e->Attribute);
+ }
+ }
+#endif
+
//////////////////////////////////////////////
// Create command line tag
//////////////////////////////////////////////
@@ -857,29 +900,7 @@ skip_modeset:;
append_tag(info_idx, tag);
}
- //////////////////////////////////////////////
- // Create EFI memory map tag
- //////////////////////////////////////////////
-#if defined (UEFI)
- {
- if ((efi_mmap_size / efi_desc_size) > MEMMAP_MAX) {
- panic(false, "multiboot2: too many EFI memory map entries");
- }
- // Create the EFI memory map tag.
- uint32_t size = sizeof(struct multiboot_tag_efi_mmap) + efi_mmap_size;
- struct multiboot_tag_efi_mmap *mmap_tag = (struct multiboot_tag_efi_mmap *)(mb2_info + info_idx);
-
- mmap_tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
- mmap_tag->descr_vers = efi_desc_ver;
- mmap_tag->descr_size = efi_desc_size;
- mmap_tag->size = size;
-
- // Copy over the EFI memory map.
- memcpy(mmap_tag->efi_mmap, efi_mmap, efi_mmap_size);
- append_tag(info_idx, mmap_tag);
- }
-#endif
//////////////////////////////////////////////
// Create network info tag
I could verify that at least the first 8 entries (couldn't get more output, see above) are equal to what my Rust binary kernel finds in multiboot_tag_mmap
(not multiboot_tag_efi_mmap
).
However, multiboot_tag_efi_mmap
reports the correct length and desc_size, but it contains just gibberish.
At this point I can say that it is not the multiboot2
crate as it is thoroughly tested.
Observations:
multiboot_tag_mmap
by transforming the EFI memory map into the old formatI wish I could provide you a minimal example. For now, all I got is this:
which you can run using nix-shell --run "integration-test/run.sh"; cat integration-test/serial.txt
In the output (if you scroll a little up) you can see how the corrupted EFI memory map is printed).
I added prints here https://github.com/limine-bootloader/limine/blob/c204af454fc9c11b8ef3633664b6e03817c33ff1/test/multiboot2.c#L102 and it outputs perfectly fine.
Just make the test image and run the multiboot2 test from the boot menu, you'll get console output via port 0xe9
.
Ah, the debugcon device. Nice, thanks! Didn't know the function e9_printf() exists.
PS: I was talking about output from the bootloader, not the multiboot2 test binary! I had to move e9print.h
and e9print.c
to common
so that I can use it from common/protos/multiboot2.c
- it works. I hope I can find any insights
In that case you could've built Limine with E9_OUTPUT=true
passed to make
(do a make clean
first).
Please have a look at https://github.com/limine-bootloader/limine/pull/358 - the provided log clearly shows that there is a bug
Yes but that's an issue with the printf function we use for testing (which barely works for 32-bit code which this is, since it was made originally as a quick and dirty 64-bit code printf), other than that, the actual values of the memory map look good to me.
The reason they don't look good to you is that the code you posted prints them all at once instead of on several separate printf calls unlike my code.
I'll close this as it is most likely an invalid issue.
Hi, I'm currently not sure where the problem is and maybe you have something helpful to say. I think Limine might have a bug when it comes to the EFI memory map and Multiboot2.
VM configuration
I'm booting a QEMU x86_64 VM with the q35 machine type, 128MB of RAM, and OVMF as UEFI-firmware in version
202402
. The firmware boots Limine 7.5.2 from a hybrid ISO image. (I think that Limine boots the legacy way as OVMF has the Compatibility Support Module (CSM) active, hence, the .EFI file is not touched.)Limine Payload
Limine than boots a Multiboot2 binary which is mapped straight into memory without any relocation at 16MB. The handoff happens in i386 32-bit protected machine state without paging.
In that payload, the EFI memory map coming from the Multiboot Boot Information (MBI) is corrupt. The relevant output, containing the regular memory map (which seems fine) and the EFI memory map, is the following:
The tags from the MBI:
Note that the
efi_memory_map
seems to be suspiously big.Printed legacy memory map (seems fine):
Printed EFI memory map (seems odd):
I'm confident that it is not a bug of my code. Especially the multiboot2 code is heavily unit- and integration tested. And I don't have any other weird side-effects.
Do you think, it could be that Limine somehow messes with the EFI mmap?