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

Allow elfloader to put kernel images directly after firmware on RISCV #135

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

kent-mcleod
Copy link
Member

@kent-mcleod kent-mcleod commented Feb 1, 2022

opensbi puts the elfloader in a fixed location right after it in memory which is where we normally wish to place the kernel with the elfloader higher in memory. This allows the kernel to immediately reclaim the elfloader memory and slightly reduces memory fragmentation by allowing the kernel reserved memory to be located next to the opensbi reserved memory and all memory after free for application use.

Test with: seL4/seL4#759

@lsf37
Copy link
Member

lsf37 commented Feb 1, 2022

I'm not deep enough in the RISCV details to review this one, but I am in favour of the general idea.

return (char *)0;
}

/* Check that the current image location doesn't overlap with the
Copy link
Contributor

Choose a reason for hiding this comment

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

we could copy backwards if they overlap, just not sure if that is necessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually the memmove implementation in the elfloader can handle this. I originally thought that it was just the same implementation of memcpy. I can fix this up to handle overlap apart from the code segment apart so that it's like the original assembly (which I originally thought was not properly handling overlap).

Copy link
Member

Choose a reason for hiding this comment

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

Isn't the issue when there is overlapping, there is chance that the code that is currently executing is not overwritten and thus the result might be undefined? So this must be detected and avoided. Same for overwriting the stack/global in bss

Copy link
Member Author

Choose a reason for hiding this comment

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

I've fixed this up to only check for collision up until _archive_start.

@@ -89,11 +91,6 @@ static int map_kernel_window(struct image_info *kernel_info)

/* Map the elfloader into the new address space */

if (!IS_ALIGNED((uintptr_t)_text, PT_LEVEL_2_BITS)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

could you explain why the check existed previously and why it can be removed a bit?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because the kernel also could only handle setting up the kernel mappings if the image was on a page boundary and because the elfloader was always placed on a page boundary by the bbl/opensbi implementation. The rest of map_kernel_window was specialized to these assumptions and so had the checks to catch when there was divergence. Now that divergence can be handled by the code, the checks should be able to be removed.

@@ -49,9 +49,6 @@ function(ApplyData61ElfLoaderSettings kernel_platform kernel_sel4_arch)
if(KernelPlatformZynqmp AND KernelSel4ArchAarch32)
set(IMAGE_START_ADDR 0x8000000 CACHE INTERNAL "" FORCE)
endif()
if(KernelPlatformSpike AND KernelSel4ArchRiscV32)
set(IMAGE_START_ADDR 0x80400000 CACHE INTERNAL "" FORCE)
Copy link
Contributor

Choose a reason for hiding this comment

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

this can be removed because of the DTS overlay change in another PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yea, it was being ignored by opensbi before and wasn't having any effect.

@kent-mcleod
Copy link
Member Author

These changes also allow the issue underlying #76 to be resolved.

@kent-mcleod
Copy link
Member Author

This relocation needs to consider the DTB passed through from opensbi when doing relocations otherwise it could get overwritten. This is an outstanding issue on Arm (https://sel4.atlassian.net/browse/SELFOUR-2138)

Porting from assembly to a higher level language makes this function
more portable.

Signed-off-by: Kent McLeod <[email protected]>
It's not necessary to require the kernel and ELFloader images are loaded
at the start of page boundaries.

Signed-off-by: Kent McLeod <[email protected]>
When booting via opensbi, the image format is a binary image and so if
the .bss section is at the end it must be initialized unconditionally.

Signed-off-by: Kent McLeod <[email protected]>
This reverts commit 8de8c9f.

Signed-off-by: Kent McLeod <[email protected]>
The SBI implementation usually loads the elfloader where the kernel
would prefer to also be loaded. Allow the elfloader to move itself to a
higher address before loading the kernel and user images.
This requires ensuring that the stacks are not overwritten during the
merge, and so must be placed before the _archive_cpio section in the
linker script.

Signed-off-by: Kent McLeod <[email protected]>
@kent-mcleod
Copy link
Member Author

This relocation needs to consider the DTB passed through from opensbi when doing relocations otherwise it could get overwritten. This is an outstanding issue on Arm (https://sel4.atlassian.net/browse/SELFOUR-2138)

This is now handled by the most recent commit.

If a DTB has been passed in from an earlier stage boot loader during an
elfloader image relocation, make sure that it doesn't get overwritten.

On Arm this isn't relevant as the protocol when relocation happens
doesn't also pass in a DTB.

Signed-off-by: Kent McLeod <[email protected]>
@@ -344,6 +344,8 @@ if(DEFINED KernelDTBPath)
set_property(SOURCE src/drivers/driver.c PROPERTY OBJECT_DEPENDS ${DEVICES_GEN_H})
endif()

set_property(SOURCE src/common.c PROPERTY OBJECT_DEPENDS ${IMAGE_START_ADDR_H})
Copy link
Member

Choose a reason for hiding this comment

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

Is this really necessary? With this PR #include <image_start_addr.h> is added to common.c, so it should be part of the normal dependency generation.



/* Perform the move and clean/invalidate caches if necessary */
char *ret = memmove(target_base, load_base, image_size);
Copy link
Member

Choose a reason for hiding this comment

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

Drop ret and use target_base instead, so it's easier to understand what this does. We could assert ro abort if memmove() does not return target_base, because that indicated something is terribly broken.

@@ -26,12 +23,13 @@ BEGIN_FUNC(_start)
* Binary images may not be loaded in the correct location.
* Try and move ourselves so we're in the right place.
*/
mov x0, #0 /* Arg 0 of fixup_image_base is NULL */
Copy link
Member

Choose a reason for hiding this comment

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

Isn't there a possibility on ARM also that we get passed a DTB here, and thus we have to check that it's not overwritten?

char *fixup_image_base(char const *fdt)
{
char *load_base = _start;
char *target_base = (char *) IMAGE_START_ADDR;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
char *target_base = (char *) IMAGE_START_ADDR;
char *target_base = (char *)IMAGE_START_ADDR;

@@ -57,7 +59,10 @@ unsigned long l2pt[PTES_PER_PT] __attribute__((aligned(4096)));
unsigned long l2pt_elf[PTES_PER_PT] __attribute__((aligned(4096)));
#endif

char elfloader_stack_alloc[BIT(CONFIG_KERNEL_STACK_BITS)];
/* This stack cannot go in the .bss section because it's already in use when the
* .bss section is zeroed.
Copy link
Member

Choose a reason for hiding this comment

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

I wonder, don't we have the same problem on ARM also then? Seem implementing clear_bss in assembly, so it does not use a stack is the cleanest way to avoid running into issues here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants