2 * This file is part of the coreboot project.
4 * Copyright (C) 2012 ChromeOS Authors
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
22 #include <console/console.h>
23 #include <program_loading.h>
26 /* Change this define to get more verbose debugging for module loading. */
27 #define PK_ADJ_LEVEL BIOS_NEVER
29 static inline int rmodule_is_loaded(const struct rmodule
*module
)
31 return module
->location
!= NULL
;
34 /* Calculate a loaded program address based on the blob address. */
35 static inline void *rmodule_load_addr(const struct rmodule
*module
,
38 char *loc
= module
->location
;
39 return &loc
[blob_addr
- module
->header
->module_link_start_address
];
42 /* Initialize a rmodule structure based on raw data. */
43 int rmodule_parse(void *ptr
, struct rmodule
*module
)
46 struct rmodule_header
*rhdr
;
54 /* Sanity check the raw data. */
55 if (rhdr
->magic
!= RMODULE_MAGIC
)
57 if (rhdr
->version
!= RMODULE_VERSION_1
)
60 /* Indicate the module hasn't been loaded yet. */
61 module
->location
= NULL
;
63 /* The rmodule only needs a reference to the reloc_header. */
64 module
->header
= rhdr
;
66 /* The payload lives after the header. */
67 module
->payload
= &base
[rhdr
->payload_begin_offset
];
68 module
->payload_size
= rhdr
->payload_end_offset
-
69 rhdr
->payload_begin_offset
;
70 module
->relocations
= &base
[rhdr
->relocations_begin_offset
];
75 int rmodule_memory_size(const struct rmodule
*module
)
77 return module
->header
->module_program_size
;
80 void *rmodule_parameters(const struct rmodule
*module
)
82 if (!rmodule_is_loaded(module
))
85 /* Indicate if there are no parameters. */
86 if (module
->header
->parameters_begin
== module
->header
->parameters_end
)
89 return rmodule_load_addr(module
, module
->header
->parameters_begin
);
92 int rmodule_entry_offset(const struct rmodule
*module
)
94 return module
->header
->module_entry_point
-
95 module
->header
->module_link_start_address
;
98 void *rmodule_entry(const struct rmodule
*module
)
100 if (!rmodule_is_loaded(module
))
103 return rmodule_load_addr(module
, module
->header
->module_entry_point
);
106 static void rmodule_clear_bss(struct rmodule
*module
)
111 begin
= rmodule_load_addr(module
, module
->header
->bss_begin
);
112 size
= module
->header
->bss_end
- module
->header
->bss_begin
;
113 memset(begin
, 0, size
);
116 static inline size_t rmodule_number_relocations(const struct rmodule
*module
)
120 r
= module
->header
->relocations_end_offset
;
121 r
-= module
->header
->relocations_begin_offset
;
122 r
/= sizeof(uintptr_t);
126 static void rmodule_copy_payload(const struct rmodule
*module
)
128 printk(BIOS_DEBUG
, "Loading module at %p with entry %p. "
129 "filesize: 0x%x memsize: 0x%x\n",
130 module
->location
, rmodule_entry(module
),
131 module
->payload_size
, rmodule_memory_size(module
));
133 /* No need to copy the payload if the load location and the
134 * payload location are the same. */
135 if (module
->location
== module
->payload
)
138 memcpy(module
->location
, module
->payload
, module
->payload_size
);
141 static int rmodule_relocate(const struct rmodule
*module
)
143 size_t num_relocations
;
144 const uintptr_t *reloc
;
145 uintptr_t adjustment
;
147 /* Each relocation needs to be adjusted relative to the beginning of
148 * the loaded program. */
149 adjustment
= (uintptr_t)rmodule_load_addr(module
, 0);
151 reloc
= module
->relocations
;
152 num_relocations
= rmodule_number_relocations(module
);
154 printk(BIOS_DEBUG
, "Processing %zu relocs. Offset value of 0x%08lx\n",
155 num_relocations
, (unsigned long)adjustment
);
157 while (num_relocations
> 0) {
158 uintptr_t *adjust_loc
;
160 /* If the adjustment location is non-NULL adjust it. */
161 adjust_loc
= rmodule_load_addr(module
, *reloc
);
162 printk(PK_ADJ_LEVEL
, "Adjusting %p: 0x%08lx -> 0x%08lx\n",
163 adjust_loc
, (unsigned long) *adjust_loc
,
164 (unsigned long) (*adjust_loc
+ adjustment
));
165 *adjust_loc
+= adjustment
;
174 int rmodule_load_alignment(const struct rmodule
*module
)
176 /* The load alignment is the start of the program's linked address.
177 * The base address where the program is loaded needs to be a multiple
178 * of the program's starting link address. That way all data alignment
179 * in the program is preserved. Default to 4KiB. */
183 int rmodule_load(void *base
, struct rmodule
*module
)
186 * In order to load the module at a given address, the following steps
188 * 1. Copy payload to base address.
189 * 2. Adjust relocations within the module to new base address.
190 * 3. Clear the bss segment last since the relocations live where
191 * the bss is. If an rmodule is being loaded from its load
192 * address the relocations need to be processed before the bss.
194 module
->location
= base
;
195 rmodule_copy_payload(module
);
196 if (rmodule_relocate(module
))
198 rmodule_clear_bss(module
);
200 prog_segment_loaded((uintptr_t)module
->location
,
201 rmodule_memory_size(module
), SEG_FINAL
);
206 int rmodule_calc_region(unsigned int region_alignment
, size_t rmodule_size
,
207 size_t *region_size
, int *load_offset
)
209 /* region_alignment must be a power of 2. */
210 if (region_alignment
& (region_alignment
- 1))
213 if (region_alignment
< 4096)
214 region_alignment
= 4096;
216 /* Sanity check rmodule_header size. The code below assumes it is less
217 * than the minimum alignment required. */
218 if (region_alignment
< sizeof(struct rmodule_header
))
221 /* Place the rmodule according to alignment. The rmodule files
222 * themselves are packed as a header and a payload, however the rmodule
223 * itself is linked along with the header. The header starts at address
224 * 0. Immediately following the header in the file is the program,
225 * however its starting address is determined by the rmodule linker
226 * script. In short, sizeof(struct rmodule_header) can be less than
227 * or equal to the linked address of the program. Therefore we want
228 * to place the rmodule so that the program falls on the aligned
229 * address with the header just before it. Therefore, we need at least
230 * a page to account for the size of the header. */
231 *region_size
= ALIGN(rmodule_size
+ region_alignment
, 4096);
232 /* The program starts immediately after the header. However,
233 * it needs to be aligned to a 4KiB boundary. Therefore, adjust the
234 * program location so that the program lands on a page boundary. The
235 * layout looks like the following:
237 * +--------------------------------+ region_alignment + region_size
238 * | >= 0 bytes from alignment |
239 * +--------------------------------+ program end (4KiB aligned)
241 * +--------------------------------+ program_begin (4KiB aligned)
242 * | sizeof(struct rmodule_header) |
243 * +--------------------------------+ rmodule header start
244 * | >= 0 bytes from alignment |
245 * +--------------------------------+ region_alignment
247 *load_offset
= region_alignment
;
249 return region_alignment
- sizeof(struct rmodule_header
);
252 int rmodule_stage_load(struct rmod_stage_load
*rsl
)
254 struct rmodule rmod_stage
;
259 struct cbfs_stage stage
;
261 struct region_device
*fh
;
263 if (rsl
->prog
== NULL
|| prog_name(rsl
->prog
) == NULL
)
266 fh
= prog_rdev(rsl
->prog
);
268 if (rdev_readat(fh
, &stage
, 0, sizeof(stage
)) != sizeof(stage
))
272 rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE
,
273 stage
.memlen
, ®ion_size
, &load_offset
);
275 stage_region
= cbmem_add(rsl
->cbmem_id
, region_size
);
277 if (stage_region
== NULL
)
280 rmod_loc
= &stage_region
[rmodule_offset
];
282 printk(BIOS_INFO
, "Decompressing stage %s @ 0x%p (%d bytes)\n",
283 prog_name(rsl
->prog
), rmod_loc
, stage
.memlen
);
285 if (!cbfs_load_and_decompress(fh
, sizeof(stage
), stage
.len
, rmod_loc
,
286 stage
.memlen
, stage
.compression
))
289 if (rmodule_parse(rmod_loc
, &rmod_stage
))
292 if (rmodule_load(&stage_region
[load_offset
], &rmod_stage
))
295 prog_set_area(rsl
->prog
, rmod_stage
.location
,
296 rmodule_memory_size(&rmod_stage
));
297 prog_set_entry(rsl
->prog
, rmodule_entry(&rmod_stage
), NULL
);
299 /* Allow caller to pick up parameters, if available. */
300 rsl
->params
= rmodule_parameters(&rmod_stage
);