coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
fit_payload.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
4 #include <console/console.h>
5 #include <bootmem.h>
6 #include <program_loading.h>
7 #include <fit.h>
8 #include <endian.h>
9 
10 /* Implements a Berkeley Boot Loader (BBL) compatible payload loading */
11 
12 #define MAX_KERNEL_SIZE (64*MiB)
13 
14 #if CONFIG(ARCH_RISCV_RV32)
15 #define SECTION_ALIGN (4 * MiB)
16 #endif
17 #if CONFIG(ARCH_RISCV_RV64)
18 #define SECTION_ALIGN (2 * MiB)
19 #endif
20 
21 static size_t get_kernel_size(const struct fit_image_node *node)
22 {
23  /*
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.
29  */
30 
32  "FIT: Leaving additional %u MiB of free space after kernel.\n",
33  MAX_KERNEL_SIZE >> 20);
34 
35  return node->size + MAX_KERNEL_SIZE;
36 }
37 
38 /**
39  * Place the region in free memory range.
40  *
41  * The caller has to set region->offset to the minimum allowed address.
42  */
43 static bool fit_place_mem(const struct range_entry *r, void *arg)
44 {
45  struct region *region = arg;
46  resource_t start;
47 
48  if (range_entry_tag(r) != BM_MEM_RAM)
49  return true;
50 
51  /* Section must be aligned at page boundary */
52  start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), SECTION_ALIGN);
53 
54  if (start + region->size < range_entry_end(r)) {
55  region->offset = (size_t)start;
56  return false;
57  }
58 
59  return true;
60 }
61 
62 bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
63  struct region *kernel,
64  struct region *fdt,
65  struct region *initrd)
66 {
67  void *arg = NULL;
68 
69  if (!config->fdt || !fdt) {
70  printk(BIOS_CRIT, "CRIT: Providing a valid FDT is mandatory to "
71  "boot a RISC-V kernel!\n");
72  return false;
73  /* TODO: Fall back to the ROM FDT? */
74  }
75 
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",
79  kernel->size);
80 
81  /*
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.
87  */
88  kernel->offset = 0;
89  if (!bootmem_walk(fit_place_mem, kernel))
90  return false;
91 
92  /* Mark as reserved for future allocations. */
93  bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);
94 
95  /* Place FDT and INITRD after kernel. */
96 
97  /* Place INITRD */
98  if (config->ramdisk) {
99  initrd->offset = kernel->offset + kernel->size;
100 
101  if (!bootmem_walk(fit_place_mem, initrd))
102  return false;
103  /* Mark as reserved for future allocations. */
104  bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD);
105  }
106 
107  /* Place FDT */
108  fdt->offset = kernel->offset + kernel->size;
109 
110  if (!bootmem_walk(fit_place_mem, fdt))
111  return false;
112  /* Mark as reserved for future allocations. */
114 
115  /* Kernel expects FDT as argument */
116  arg = (void *)fdt->offset;
117 
118  prog_set_entry(payload, (void *)kernel->offset, arg);
119 
121 
122  return true;
123 }
bool fit_payload_arch(struct prog *payload, struct fit_config_node *config, struct region *kernel, struct region *fdt, struct region *initrd)
Definition: fit_payload.c:30
static bool fit_place_mem(const struct range_entry *r, void *arg)
Place the region in free memory range.
Definition: fit_payload.c:43
#define MAX_KERNEL_SIZE
Definition: fit_payload.c:12
static size_t get_kernel_size(const struct fit_image_node *node)
Definition: fit_payload.c:21
void bootmem_dump_ranges(void)
Definition: bootmem.c:155
@ BM_MEM_RAM
Definition: bootmem.h:23
@ BM_MEM_PAYLOAD
Definition: bootmem.h:35
void bootmem_add_range(uint64_t start, uint64_t size, const enum bootmem_type tag)
Definition: bootmem.c:88
bool bootmem_walk(range_action_t action, void *arg)
Walk memory tables and call the provided function, for every region.
Definition: bootmem.c:183
#define MAX(a, b)
Definition: helpers.h:40
#define ALIGN_UP(x, a)
Definition: helpers.h:17
#define printk(level,...)
Definition: stdlib.h:16
struct bootblock_arg arg
Definition: decompressor.c:22
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_CRIT
BIOS_CRIT - Recovery unlikely.
Definition: loglevel.h:56
enum board_config config
Definition: memory.c:448
static resource_t range_entry_base(const struct range_entry *r)
Definition: memrange.h:44
static resource_t range_entry_end(const struct range_entry *r)
Definition: memrange.h:50
static unsigned long range_entry_tag(const struct range_entry *r)
Definition: memrange.h:61
static void prog_set_entry(struct prog *prog, void *e, void *arg)
u64 resource_t
Definition: resource.h:43
#define NULL
Definition: stddef.h:19
__SIZE_TYPE__ size_t
Definition: stddef.h:7
uint32_t size
Definition: fit.h:16
Definition: memrange.h:24
Definition: region.h:76
size_t size
Definition: region.h:78
size_t offset
Definition: region.h:77