aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMasahiro Yamada2017-03-09 16:28:25 +0900
committerTom Rini2017-03-14 20:40:23 -0400
commit2808576491ae36b6ea96743005058f370d936beb (patch)
treedbde878c68a528f04cc709ea5f918379531bb503
parent3b0825296aeba69c2cbfd3e179db2e9cbe5e70d7 (diff)
arm64: booti: allow to place kernel image anywhere in physical memory
At first, the ARM64 Linux booting requirement recommended that the kernel image be placed text_offset bytes from 2MB aligned base near the start of usable system RAM because memory below that base address was unusable at that time. This requirement was relaxed by Linux commit a7f8de168ace ("arm64: allow kernel Image to be loaded anywhere in physical memory"). Since then, the bit 3 of the flags field indicates the tolerance of the kernel physical placement. If this bit is set, the 2MB aligned base may be anywhere in physical memory. For details, see Documentation/arm64/booting.txt of Linux. The booti command should be also relaxed. If the bit 3 is set, images->ep is respected, and the image is placed at the nearest bootable location. Otherwise, it is relocated to the start of the system RAM to keep the original behavior. Another wrinkle we need to take care of is the unknown endianness of text_offset for a kernel older than commit a2c1d73b94ed (i.e. v3.16). We can detect this based on the image_size field. If the field is zero, just use a fixed offset 0x80000. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
-rw-r--r--cmd/booti.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/cmd/booti.c b/cmd/booti.c
index bff87a8acc1..da6fb01c11d 100644
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -11,6 +11,8 @@
#include <image.h>
#include <lmb.h>
#include <mapmem.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -20,7 +22,7 @@ struct Image_header {
uint32_t code1; /* Executable code */
uint64_t text_offset; /* Image load offset, LE */
uint64_t image_size; /* Effective Image size, LE */
- uint64_t res1; /* reserved */
+ uint64_t flags; /* Kernel flags, LE */
uint64_t res2; /* reserved */
uint64_t res3; /* reserved */
uint64_t res4; /* reserved */
@@ -34,7 +36,7 @@ static int booti_setup(bootm_headers_t *images)
{
struct Image_header *ih;
uint64_t dst;
- uint64_t image_size;
+ uint64_t image_size, text_offset;
ih = (struct Image_header *)map_sysmem(images->ep, 0);
@@ -42,19 +44,33 @@ static int booti_setup(bootm_headers_t *images)
puts("Bad Linux ARM64 Image magic!\n");
return 1;
}
-
+
+ /*
+ * Prior to Linux commit a2c1d73b94ed, the text_offset field
+ * is of unknown endianness. In these cases, the image_size
+ * field is zero, and we can assume a fixed value of 0x80000.
+ */
if (ih->image_size == 0) {
puts("Image lacks image_size field, assuming 16MiB\n");
image_size = 16 << 20;
+ text_offset = 0x80000;
} else {
image_size = le64_to_cpu(ih->image_size);
+ text_offset = le64_to_cpu(ih->text_offset);
}
/*
- * If we are not at the correct run-time location, set the new
- * correct location and then move the image there.
+ * If bit 3 of the flags field is set, the 2MB aligned base of the
+ * kernel image can be anywhere in physical memory, so respect
+ * images->ep. Otherwise, relocate the image to the base of RAM
+ * since memory below it is not accessible via the linear mapping.
*/
- dst = gd->bd->bi_dram[0].start + le64_to_cpu(ih->text_offset);
+ if (le64_to_cpu(ih->flags) & BIT(3))
+ dst = images->ep - text_offset;
+ else
+ dst = gd->bd->bi_dram[0].start;
+
+ dst = ALIGN(dst, SZ_2M) + text_offset;
unmap_sysmem(ih);