int rmodule_stage_load(struct rmod_stage_load *rsl) { struct rmodule rmod_stage; size_t region_size; char *stage_region; int rmodule_offset; int load_offset; struct cbfs_stage stage; void *rmod_loc; struct region_device *fh; if (rsl->prog == NULL || prog_name(rsl->prog) == NULL) return -1; fh = prog_rdev(rsl->prog); if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage)) return -1; rmodule_offset = rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, stage.memlen, ®ion_size, &load_offset); stage_region = cbmem_add(rsl->cbmem_id, region_size); if (stage_region == NULL) return -1; rmod_loc = &stage_region[rmodule_offset]; printk(BIOS_INFO, "Decompressing stage %s @ 0x%p (%d bytes)\n", prog_name(rsl->prog), rmod_loc, stage.memlen); if (!cbfs_load_and_decompress(fh, sizeof(stage), stage.len, rmod_loc, stage.memlen, stage.compression)) return -1; if (rmodule_parse(rmod_loc, &rmod_stage)) return -1; if (rmodule_load(&stage_region[load_offset], &rmod_stage)) return -1; prog_set_area(rsl->prog, rmod_stage.location, rmodule_memory_size(&rmod_stage)); prog_set_entry(rsl->prog, rmodule_entry(&rmod_stage), NULL); /* Allow caller to pick up parameters, if available. */ rsl->params = rmodule_parameters(&rmod_stage); return 0; }
static void rmodule_copy_payload(const struct rmodule *module) { printk(BIOS_DEBUG, "Loading module at %p with entry %p. " "filesize: 0x%x memsize: 0x%x\n", module->location, rmodule_entry(module), module->payload_size, rmodule_memory_size(module)); /* No need to copy the payload if the load location and the * payload location are the same. */ if (module->location == module->payload) return; memcpy(module->location, module->payload, module->payload_size); }
int rmodule_load(void *base, struct rmodule *module) { /* * In order to load the module at a given address, the following steps * take place: * 1. Copy payload to base address. * 2. Adjust relocations within the module to new base address. * 3. Clear the bss segment last since the relocations live where * the bss is. If an rmodule is being loaded from its load * address the relocations need to be processed before the bss. */ module->location = base; rmodule_copy_payload(module); if (rmodule_relocate(module)) return -1; rmodule_clear_bss(module); prog_segment_loaded((uintptr_t)module->location, rmodule_memory_size(module), SEG_FINAL); return 0; }
int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage) { struct rmodule rmod_stage; size_t region_size; char *stage_region; int rmodule_offset; int load_offset; if (stage == NULL || rsl->prog == NULL || rsl->prog->name == NULL) return -1; rmodule_offset = rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, stage->memlen, ®ion_size, &load_offset); stage_region = cbmem_add(rsl->cbmem_id, region_size); if (stage_region == NULL) return -1; printk(BIOS_INFO, "Decompressing stage %s @ 0x%p (%d bytes)\n", rsl->prog->name, &stage_region[rmodule_offset], stage->memlen); if (!cbfs_decompress(stage->compression, &stage[1], &stage_region[rmodule_offset], stage->len)) return -1; if (rmodule_parse(&stage_region[rmodule_offset], &rmod_stage)) return -1; if (rmodule_load(&stage_region[load_offset], &rmod_stage)) return -1; prog_set_area(rsl->prog, rmod_stage.location, rmodule_memory_size(&rmod_stage)); prog_set_entry(rsl->prog, rmodule_entry(&rmod_stage), NULL); return 0; }