summaryrefslogtreecommitdiffstats
path: root/src/soc/amd/common/block/pi/refcode_loader.c
blob: 2fdbe833476b93b830419e8f0e7e322ee6e1f528 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* SPDX-License-Identifier: GPL-2.0-only */

#include <acpi/acpi.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
#include <rmodule.h>
#include <stage_cache.h>
#include <amdblocks/agesawrapper.h>
#include <amdblocks/image.h>

static int agesa_locate_file(const char *name, struct region_device *rdev,
				uint32_t type)
{
	struct cbfsf fh;

	if (cbfs_boot_locate(&fh, name, &type))
		return -1;

	cbfs_file_data(rdev, &fh);
	return 0;
}

static int agesa_locate_raw_file(const char *name, struct region_device *rdev)
{
	return agesa_locate_file(name, rdev, CBFS_TYPE_RAW);
}

static int agesa_locate_stage_file_early(const char *name,
					struct region_device *rdev)
{
	const size_t metadata_sz = sizeof(struct cbfs_stage);

	if (agesa_locate_file(name, rdev, CBFS_TYPE_STAGE))
		return -1;

	/* Peel off the cbfs stage metadata. */
	return rdev_chain(rdev, rdev, metadata_sz,
			region_device_sz(rdev) - metadata_sz);
}

static int agesa_locate_stage_file_ramstage(const char *name,
						struct region_device *rdev)
{
	struct prog prog = PROG_INIT(PROG_REFCODE, name);
	struct rmod_stage_load rmod_agesa = {
		.cbmem_id = CBMEM_ID_REFCODE,
		.prog = &prog,
	};

	if (acpi_is_wakeup_s3() && !CONFIG(NO_STAGE_CACHE)) {
		printk(BIOS_INFO, "AGESA: Loading stage from cache\n");
		// There is no way to tell if this succeeded.
		stage_cache_load_stage(STAGE_REFCODE, &prog);
	} else {
		if (prog_locate(&prog))
			return -1;

		if (rmodule_stage_load(&rmod_agesa) < 0)
			return -1;

		if (!CONFIG(NO_STAGE_CACHE)) {
			printk(BIOS_INFO, "AGESA: Saving stage to cache\n");
			stage_cache_add(STAGE_REFCODE, &prog);
		}
	}

	return rdev_chain(rdev, prog_rdev(&prog), 0,
		region_device_sz(prog_rdev(&prog)));
}

static int agesa_locate_stage_file(const char *name, struct region_device *rdev)
{
	if (!ENV_RAMSTAGE || !CONFIG(AGESA_SPLIT_MEMORY_FILES))
		return agesa_locate_stage_file_early(name, rdev);
	return agesa_locate_stage_file_ramstage(name, rdev);
}

static const char *get_agesa_cbfs_name(void)
{
	if (!CONFIG(AGESA_SPLIT_MEMORY_FILES))
		return CONFIG_AGESA_CBFS_NAME;
	if (!ENV_RAMSTAGE)
		return CONFIG_AGESA_PRE_MEMORY_CBFS_NAME;
	return CONFIG_AGESA_POST_MEMORY_CBFS_NAME;
}

const void *agesawrapper_locate_module(const char name[8])
{
	const void *agesa;
	const AMD_IMAGE_HEADER *image;
	struct region_device rdev;
	size_t file_size;
	const char *fname;
	int ret;

	fname = get_agesa_cbfs_name();

	if (CONFIG(AGESA_BINARY_PI_AS_STAGE))
		ret = agesa_locate_stage_file(fname, &rdev);
	else
		ret = agesa_locate_raw_file(fname, &rdev);

	if (ret)
		return NULL;

	file_size = region_device_sz(&rdev);

	/* Assume boot device is memory mapped so the mapping can leak. */
	assert(CONFIG(BOOT_DEVICE_MEMORY_MAPPED));

	agesa = rdev_mmap_full(&rdev);

	if (!agesa)
		return NULL;

	image =  amd_find_image(agesa, agesa + file_size, 4096, name);

	if (!image)
		return NULL;

	return (AMD_MODULE_HEADER *)image->ModuleInfoOffset;
}

static MODULE_ENTRY agesa_dispatcher;

MODULE_ENTRY agesa_get_dispatcher(void)
{
	const AMD_MODULE_HEADER *module;
	static const char id[8] = AGESA_ID;

	if (agesa_dispatcher != NULL)
		return agesa_dispatcher;

	module = agesawrapper_locate_module(id);
	if (!module)
		return NULL;

	agesa_dispatcher = module->ModuleDispatcher;
	return agesa_dispatcher;
}