Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arm64: Use proper memory type for kernel allocation #101

Merged
merged 1 commit into from Aug 31, 2023

Conversation

qzed
Copy link
Contributor

@qzed qzed commented Jun 28, 2022

Currently, the kernel pages are allocated with type EFI_LOADER_DATA.
While the vast majority of systems will happily execute code from those
pages (i.e. don't care about memory protection), the Microsoft Surface
Pro X stalls, as this memory is not designated as "executable".

Therefore, allocate the kernel pages as EFI_LOADER_CODE to request
memory that is actually executable.

Signed-off-by: Maximilian Luz luzmaximilian@gmail.com

Copy link
Member

@frozencemetery frozencemetery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thank you for testing and tracking that down!

@@ -389,7 +391,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_loader_unset();

kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages);
kernel_alloc_addr = grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if isn't better to instead make grub_efi_allocate_any_pages() to use GRUB_EFI_LOADER_CODE rather than open coding it the params that use it to call grub_efi_allocate_pages_real().

Since AFAICT is only used to allocate memory for the kernel image anyways, the memory for the initrd (that's data and not code) is already allocated using a different helper allocate_initrd_mem() so that can continue to use GRUB_EFI_LOADER_DATA.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, by changing grub_efi_allocate_any_pages() you will fix this not only for arm64 but also for x86.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that it's used in grub_efi_mm_init() to allocate memory maps. How about a helper (perhaps grub_efi_allocate_executable_pages() or grub_efi_allocate_kernel_pages())?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, probably grub_efi_allocate_kernel_pages() then to be consistent with how the memory for the initrd is allocated ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i386 already has 8a2d168 (although that uses EFI_RUNTIME_SERVICES_CODE instead). I assume that's also used for x86_64?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, the EFI stub of the kernel seems more like a UEFI application than a runtime driver, but again, I don't know much about this stuff.

Yes, I agree with you here.

Copy link
Contributor Author

@qzed qzed Jun 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw: chainloader also seems to use GRUB_EFI_LOADER_CODE:

status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
GRUB_EFI_LOADER_CODE,
pages, &address);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that it's used in grub_efi_mm_init() to allocate memory maps. How about a helper (perhaps grub_efi_allocate_executable_pages() or grub_efi_allocate_kernel_pages())?

Probably just move kernel_alloc() from the i386 loader to some common code and make the policy list be passed in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems to depend on some interaction with the max_addresses field, where parts of it are read in from the i386/x64 kernel header. I'm not sure how to adapt this for AArch64, but if you have some patches I'd be happy to test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably just move kernel_alloc() from the i386 loader to some common code and make the policy list be passed in?

So after having another look at this, the max_addresses thing shouldn't be an issue. As you've said, this could just be passed in. However, I think using kernel_alloc() here doesn't make that much sense to do this in this PR:

We could use it for the kernel image + command-line memory, passing in a policy array with a single entry. But given that it only uses a single entry and none of the re-try logic that's used on x86, this seems a bit too convoluted to me. Also, it's orthogonal to the change to GRUB_EFI_LOADER_CODE, because that is still passed in to kernel_alloc(). Further, adapting it for the initrd would need some changes (or workarounds) as the arm64 code relies on grub_efi_get_ram_base() whereas the x86 code doesn't.

@ausil
Copy link

ausil commented Mar 20, 2023

Could we get this PR down to the one relevant patch for discussion, please?

@qzed
Copy link
Contributor Author

qzed commented May 8, 2023

Sorry for the long silence. I will try to revisit this in the next couple of days.

Currently, the kernel pages are allocated with type EFI_LOADER_DATA.
While the vast majority of systems will happily execute code from those
pages (i.e. don't care about memory protection), the Microsoft Surface
Pro X stalls, as this memory is not designated as "executable".

Therefore, allocate the kernel pages as EFI_LOADER_CODE to request
memory that is actually executable.

Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
@qzed qzed changed the base branch from fedora-38 to fedora-39 May 15, 2023 14:34
@jlinton
Copy link

jlinton commented Jul 31, 2023

The current version of this code also fixes the lenovo x13s, and presumably other machines based on the QC SoC/firmware. It also matches a bit of debugging/hacking I did last week before being pointed at this PR. My only reservations are that maybe it should only be done on machines that don't have the EFI_MEMORY_ATTRIBUTE_PROTOCOL. I have a slight worry there are some old/unsupported machines that have +Write turned off for EfiLoaderCode pages, but at the moment we have a known set of broken machines without this change.

Is there a more concrete problem with it?

@nfrayer nfrayer self-requested a review August 29, 2023 10:37
Copy link
Contributor

@nfrayer nfrayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@nfrayer nfrayer merged commit 4f9d3f4 into rhboot:fedora-39 Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants