static int smm_module_setup_stub(void *smbase, size_t smm_size,
				 struct smm_loader_params *params,
				 void *fxsave_area)
{
	size_t total_save_state_size;
	size_t smm_stub_size;
	size_t stub_entry_offset;
	char *smm_stub_loc;
	void *stacks_top;
	size_t size;
	char *base;
	size_t i;
	struct smm_stub_params *stub_params;
	struct rmodule smm_stub;
	unsigned int total_size_all;
	base = smbase;
	size = smm_size;

	/* The number of concurrent stacks cannot exceed CONFIG_MAX_CPUS. */
	if (params->num_concurrent_stacks > CONFIG_MAX_CPUS) {
		printk(BIOS_ERR, "%s: not enough stacks\n", __func__);
		return -1;
	}

	/* Fail if can't parse the smm stub rmodule. */
	if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) {
		printk(BIOS_ERR, "%s: unable to parse smm stub\n", __func__);
		return -1;
	}

	/* Adjust remaining size to account for save state. */
	total_save_state_size = params->per_cpu_save_state_size *
				params->num_concurrent_save_states;
	if (total_save_state_size > size) {
		printk(BIOS_ERR,
			"%s: more state save space needed:need -> %zx:available->%zx\n",
			__func__, total_save_state_size, size);
		return -1;
	}

	size -= total_save_state_size;

	/* The save state size encroached over the first SMM entry point. */
	if (size <= params->smm_main_entry_offset) {
		printk(BIOS_ERR, "%s: encroachment over SMM entry point\n", __func__);
		printk(BIOS_ERR, "%s: state save size: %zx : smm_entry_offset -> %x\n",
			__func__, size, params->smm_main_entry_offset);
		return -1;
	}

	/* Need a minimum stack size and alignment. */
	if (params->per_cpu_stack_size <= SMM_MINIMUM_STACK_SIZE ||
	    (params->per_cpu_stack_size & 3) != 0) {
		printk(BIOS_ERR, "%s: need minimum stack size\n", __func__);
		return -1;
	}

	smm_stub_loc = NULL;
	smm_stub_size = rmodule_memory_size(&smm_stub);
	stub_entry_offset = rmodule_entry_offset(&smm_stub);

	/* Put the stub at the main entry point */
	smm_stub_loc = &base[params->smm_main_entry_offset];

	/* Stub is too big to fit. */
	if (smm_stub_size > (size - params->smm_main_entry_offset)) {
		printk(BIOS_ERR, "%s: stub is too big to fit\n", __func__);
		return -1;
	}

	/* The stacks, if requested, live in the lower half of SMRAM space
	 * for default handler, but for relocated handler it lives at the beginning
	 * of SMRAM which is TSEG base
	 */
	size = params->num_concurrent_stacks * params->per_cpu_stack_size;
	stacks_top = smm_stub_place_stacks((char *)params->smram_start, size, params);
	if (stacks_top == NULL) {
		printk(BIOS_ERR, "%s: not enough space for stacks\n", __func__);
		printk(BIOS_ERR, "%s: ....need -> %p : available -> %zx\n", __func__,
			base, size);
		return -1;
	}
	params->stack_top = stacks_top;
	/* Load the stub. */
	if (rmodule_load(smm_stub_loc, &smm_stub)) {
		printk(BIOS_ERR, "%s: load module failed\n", __func__);
		return -1;
	}

	if (!smm_stub_place_staggered_entry_points(base, params, &smm_stub)) {
		printk(BIOS_ERR, "%s: staggered entry points failed\n", __func__);
		return -1;
	}

	/* Setup the parameters for the stub code. */
	stub_params = rmodule_parameters(&smm_stub);
	stub_params->stack_top = (uintptr_t)stacks_top;
	stub_params->stack_size = params->per_cpu_stack_size;
	stub_params->c_handler = (uintptr_t)params->handler;
	stub_params->c_handler_arg = (uintptr_t)params->handler_arg;
	stub_params->fxsave_area = (uintptr_t)fxsave_area;
	stub_params->fxsave_area_size = FXSAVE_SIZE;
	stub_params->runtime.smbase = (uintptr_t)smbase;
	stub_params->runtime.smm_size = smm_size;
	stub_params->runtime.save_state_size = params->per_cpu_save_state_size;
	stub_params->runtime.num_cpus = params->num_concurrent_stacks;

	printk(BIOS_DEBUG, "%s: stack_end = 0x%x\n",
		__func__, stub_params->runtime.smbase);
	printk(BIOS_DEBUG,
		"%s: stack_top = 0x%x\n", __func__, stub_params->stack_top);
	printk(BIOS_DEBUG, "%s: stack_size = 0x%x\n",
		__func__, stub_params->stack_size);
	printk(BIOS_DEBUG, "%s: runtime.smbase = 0x%x\n",
		__func__, stub_params->runtime.smbase);
	printk(BIOS_DEBUG, "%s: runtime.start32_offset = 0x%x\n", __func__,
		stub_params->runtime.start32_offset);
	printk(BIOS_DEBUG, "%s: runtime.smm_size = 0x%zx\n",
		__func__, smm_size);
	printk(BIOS_DEBUG, "%s: per_cpu_save_state_size = 0x%x\n",
		__func__, stub_params->runtime.save_state_size);
	printk(BIOS_DEBUG, "%s: num_cpus = 0x%x\n", __func__,
		stub_params->runtime.num_cpus);
	printk(BIOS_DEBUG, "%s: total_save_state_size = 0x%x\n",
		__func__, (stub_params->runtime.save_state_size *
		stub_params->runtime.num_cpus));
	total_size_all = stub_params->stack_size +
		(stub_params->runtime.save_state_size *
		stub_params->runtime.num_cpus);
	printk(BIOS_DEBUG, "%s: total_size_all = 0x%x\n", __func__,
		total_size_all);

	/* Initialize the APIC id to CPU number table to be 1:1 */
	for (i = 0; i < params->num_concurrent_stacks; i++)
		stub_params->runtime.apic_id_to_cpu[i] = i;

	/* Allow the initiator to manipulate SMM stub parameters. */
	params->runtime = &stub_params->runtime;

	printk(BIOS_DEBUG, "SMM Module: stub loaded at %p. Will call %p(%p)\n",
	       smm_stub_loc, params->handler, params->handler_arg);
	return 0;
}