| 192 | } |
| 193 | |
| 194 | static void *rmodule_cbfs_allocator(void *rsl_arg, size_t unused, |
| 195 | const union cbfs_mdata *mdata) |
| 196 | { |
| 197 | struct rmod_stage_load *rsl = rsl_arg; |
| 198 | |
| 199 | assert(IS_POWER_OF_2(region_alignment) && |
| 200 | region_alignment >= sizeof(struct rmodule_header)); |
| 201 | |
| 202 | /* The CBFS core just passes us the decompressed size of the file, but |
| 203 | we need to know the memlen of the binary image. We need to find and |
| 204 | parse the stage header explicitly. */ |
| 205 | const struct cbfs_file_attr_stageheader *sattr = cbfs_find_attr(mdata, |
| 206 | CBFS_FILE_ATTR_TAG_STAGEHEADER, sizeof(*sattr)); |
| 207 | if (!sattr) { |
| 208 | printk(BIOS_ERR, "rmodule '%s' has no stage header!\n", |
| 209 | rsl->prog->name); |
| 210 | return NULL; |
| 211 | } |
| 212 | |
| 213 | const size_t memlen = be32toh(sattr->memlen); |
| 214 | |
| 215 | /* Place the rmodule according to alignment. The rmodule files |
| 216 | * themselves are packed as a header and a payload, however the rmodule |
| 217 | * itself is linked along with the header. The header starts at address |
| 218 | * 0. Immediately following the header in the file is the program, |
| 219 | * however its starting address is determined by the rmodule linker |
| 220 | * script. In short, sizeof(struct rmodule_header) can be less than |
| 221 | * or equal to the linked address of the program. Therefore we want |
| 222 | * to place the rmodule so that the program falls on the aligned |
| 223 | * address with the header just before it. Therefore, we need at least |
| 224 | * a page to account for the size of the header. */ |
| 225 | size_t region_size = ALIGN_UP(memlen + region_alignment, 4096); |
| 226 | /* The program starts immediately after the header. However, |
| 227 | * it needs to be aligned to a 4KiB boundary. Therefore, adjust the |
| 228 | * program location so that the program lands on a page boundary. The |
| 229 | * layout looks like the following: |
| 230 | * |
| 231 | * +--------------------------------+ region_alignment + region_size |
| 232 | * | >= 0 bytes from alignment | |
| 233 | * +--------------------------------+ program end (4KiB aligned) |
| 234 | * | program size | |
| 235 | * +--------------------------------+ program_begin (4KiB aligned) |
| 236 | * | sizeof(struct rmodule_header) | |
| 237 | * +--------------------------------+ rmodule header start |
| 238 | * | >= 0 bytes from alignment | |
| 239 | * +--------------------------------+ region_alignment |
| 240 | */ |
| 241 | |
| 242 | uint8_t *stage_region = cbmem_add(rsl->cbmem_id, region_size); |
| 243 | if (stage_region == NULL) |
| 244 | return NULL; |
| 245 | |
| 246 | return stage_region + region_alignment - sizeof(struct rmodule_header); |
| 247 | } |
| 248 | |
| 249 | int rmodule_stage_load(struct rmod_stage_load *rsl) |
| 250 | { |
nothing calls this directly
no test coverage detected