xref: /aosp_15_r20/external/coreboot/src/arch/arm/fit_payload.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <bootmem.h>
4 #include <program_loading.h>
5 #include <fit.h>
6 #include <symbols.h>
7 
8 /**
9  * Place the region in free memory range.
10  */
fit_place_mem(const struct range_entry * r,void * arg)11 static bool fit_place_mem(const struct range_entry *r, void *arg)
12 {
13 	struct region *region = arg;
14 	resource_t start;
15 
16 	if (range_entry_tag(r) != BM_MEM_RAM)
17 		return true;
18 
19 	/* Linux 4.15 doesn't like 4KiB alignment. Align to 1 MiB for now. */
20 	start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), 1 * MiB);
21 
22 	if (start + region->size < range_entry_end(r)) {
23 		region->offset = (size_t)start;
24 		return false;
25 	}
26 
27 	return true;
28 }
29 
fit_payload_arch(struct prog * payload,struct fit_config_node * config,struct region * kernel,struct region * fdt,struct region * initrd)30 bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
31 		      struct region *kernel,
32 		      struct region *fdt,
33 		      struct region *initrd)
34 {
35 	void *arg = NULL;
36 
37 	/**
38 	 * The kernel ARM documentation recommends loading the kernel above 32MiB
39 	 * in order to avoid the need to need to relocate prior to decompression.
40 	 */
41 	kernel->offset = (uintptr_t)_dram + 32 * MiB;
42 
43 	/**
44 	 * The code assumes that bootmem_walk provides a sorted list of memory
45 	 * regions, starting from the lowest address.
46 	 * The order of the calls here doesn't matter, as the placement is
47 	 * enforced in the called functions.
48 	 * For details check code on top.
49 	 */
50 	if (!bootmem_walk(fit_place_mem, kernel))
51 		return false;
52 
53 	/* Mark as reserved for future allocations. */
54 	bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);
55 
56 	/**
57 	 * To ensure the fdt is not overwritten by the kernel decompressor, place
58 	 * the fdt above the 128 MB from the start of RAM, as recommended by the
59 	 * kernel documentation.
60 	 */
61 	fdt->offset = (uintptr_t)_dram + 128 * MiB;
62 
63 	if (!bootmem_walk(fit_place_mem, fdt))
64 		return false;
65 
66 	/* Mark as reserved for future allocations. */
67 	bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD);
68 
69 	/* Place INITRD */
70 	if (config->ramdisk) {
71 		initrd->offset = fdt->offset + fdt->size;
72 
73 		if (!bootmem_walk(fit_place_mem, initrd))
74 			return false;
75 
76 		/* Mark as reserved for future allocations. */
77 		bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD);
78 	}
79 
80 	/* Kernel expects FDT as argument */
81 	arg = (void *)fdt->offset;
82 
83 	prog_set_entry(payload, (void *)kernel->offset, arg);
84 
85 	bootmem_dump_ranges();
86 
87 	return true;
88 }
89