1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <commonlib/bsd/compression.h>
4 #include <console/console.h>
6 #include <program_loading.h>
10 /* Implements a Berkeley Boot Loader (BBL) compatible payload loading */
12 #define MAX_KERNEL_SIZE (64*MiB)
14 #if CONFIG(ARCH_RISCV_RV32)
15 #define SECTION_ALIGN (4 * MiB)
17 #if CONFIG(ARCH_RISCV_RV64)
18 #define SECTION_ALIGN (2 * MiB)
21 static size_t get_kernel_size(const struct fit_image_node
*node
)
24 * Since we don't have a way to determine the uncompressed size of the
25 * kernel, we have to keep as much memory as possible free for use by
26 * the kernel immediately after the end of the kernel image. The amount
27 * of space required will vary depending on selected features, and is
28 * effectively unbound.
32 "FIT: Leaving additional %u MiB of free space after kernel.\n",
33 MAX_KERNEL_SIZE
>> 20);
35 return node
->size
+ MAX_KERNEL_SIZE
;
39 * Place the region in free memory range.
41 * The caller has to set region->offset to the minimum allowed address.
43 static bool fit_place_mem(const struct range_entry
*r
, void *arg
)
45 struct region
*region
= arg
;
48 if (range_entry_tag(r
) != BM_MEM_RAM
)
51 /* Section must be aligned at page boundary */
52 start
= ALIGN_UP(MAX(region
->offset
, range_entry_base(r
)), SECTION_ALIGN
);
54 if (start
+ region
->size
< range_entry_end(r
)) {
55 region
->offset
= (size_t)start
;
62 bool fit_payload_arch(struct prog
*payload
, struct fit_config_node
*config
,
63 struct region
*kernel
,
65 struct region
*initrd
)
69 if (!config
->fdt
|| !fdt
) {
70 printk(BIOS_CRIT
, "Providing a valid FDT is mandatory to "
71 "boot a RISC-V kernel!\n");
73 /* TODO: Fall back to the ROM FDT? */
76 /* Update kernel size from image header, if possible */
77 kernel
->size
= get_kernel_size(config
->kernel
);
78 printk(BIOS_DEBUG
, "FIT: Using kernel size of 0x%zx bytes\n",
82 * The code assumes that bootmem_walk provides a sorted list of memory
83 * regions, starting from the lowest address.
84 * The order of the calls here doesn't matter, as the placement is
85 * enforced in the called functions.
86 * For details check code on top.
89 if (!bootmem_walk(fit_place_mem
, kernel
))
92 /* Mark as reserved for future allocations. */
93 bootmem_add_range(kernel
->offset
, kernel
->size
, BM_MEM_PAYLOAD
);
95 /* Place FDT and INITRD after kernel. */
98 if (config
->ramdisk
) {
99 initrd
->offset
= kernel
->offset
+ kernel
->size
;
101 if (!bootmem_walk(fit_place_mem
, initrd
))
103 /* Mark as reserved for future allocations. */
104 bootmem_add_range(initrd
->offset
, initrd
->size
, BM_MEM_PAYLOAD
);
108 fdt
->offset
= kernel
->offset
+ kernel
->size
;
110 if (!bootmem_walk(fit_place_mem
, fdt
))
112 /* Mark as reserved for future allocations. */
113 bootmem_add_range(fdt
->offset
, fdt
->size
, BM_MEM_PAYLOAD
);
115 /* Kernel expects FDT as argument */
116 arg
= (void *)fdt
->offset
;
118 prog_set_entry(payload
, (void *)kernel
->offset
, arg
);
120 bootmem_dump_ranges();