summaryrefslogtreecommitdiffstats
path: root/arch/x86/lib/fsp2/fsp_support.c
blob: 3f2ca840dc9506983b31bf78285a845eabfdaae9 (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
// SPDX-License-Identifier: Intel
/*
 * Copyright 2019 Google LLC
 * Written by Simon Glass <sjg@chromium.org>
 */

#include <common.h>
#include <dm.h>
#include <log.h>
#include <spi_flash.h>
#include <asm/fsp/fsp_support.h>
#include <asm/fsp2/fsp_internal.h>

/* The amount of the FSP header to probe to obtain what we need */
#define PROBE_BUF_SIZE 0x180

int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
		   struct fsp_header **fspp)
{
	static efi_guid_t guid = FSP_HEADER_GUID;
	struct fv_ext_header *exhdr;
	struct fsp_header *fsp;
	struct ffs_file_header *file_hdr;
	struct fv_header *fv;
	struct raw_section *raw;
	void *ptr, *base;
	u8 buf[PROBE_BUF_SIZE];
	struct udevice *dev;
	int ret;

	/*
	 * There are quite a very steps to work through all the headers in this
	 * file and the structs have similar names. Turn on debugging if needed
	 * to understand what is going wrong.
	 *
	 * You are in a maze of twisty little headers all alike.
	 */
	debug("offset=%x buf=%x\n", (uint)offset, (uint)buf);
	if (use_spi_flash) {
		ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
		if (ret)
			return log_msg_ret("Cannot find flash device", ret);
		ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
		if (ret)
			return log_msg_ret("Cannot read flash", ret);
	} else {
		memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
	}

	/* Initalise the FSP base */
	ptr = buf;
	fv = ptr;

	/* Check the FV signature, _FVH */
	debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
	if (fv->sign != EFI_FVH_SIGNATURE)
		return log_msg_ret("Base FV signature", -EINVAL);

	/* Go to the end of the FV header and align the address */
	debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
	ptr += fv->ext_hdr_off;
	exhdr = ptr;
	ptr += ALIGN(exhdr->ext_hdr_size, 8);
	debug("ptr=%x\n", ptr - (void *)buf);

	/* Check the FFS GUID */
	file_hdr = ptr;
	if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
		return log_msg_ret("Base FFS GUID", -ENXIO);
	/* Add the FFS header size to find the raw section header */
	ptr = file_hdr + 1;

	raw = ptr;
	debug("raw->type = %x\n", raw->type);
	if (raw->type != EFI_SECTION_RAW)
		return log_msg_ret("Section type not RAW", -ENOEXEC);

	/* Add the raw section header size to find the FSP header */
	ptr = raw + 1;
	fsp = ptr;

	/* Check the FSPH header */
	debug("fsp %x\n", (uint)fsp);
	if (fsp->sign != EFI_FSPH_SIGNATURE)
		return log_msg_ret("Base FSPH signature", -EACCES);

	base = (void *)fsp->img_base;
	debug("Image base %x\n", (uint)base);
	debug("Image addr %x\n", (uint)fsp->fsp_mem_init);
	if (use_spi_flash) {
		ret = spi_flash_read_dm(dev, offset, size, base);
		if (ret)
			return log_msg_ret("Could not read FPS-M", ret);
	} else {
		memcpy(base, (void *)offset, size);
	}
	ptr = base + (ptr - (void *)buf);
	*fspp = ptr;

	return 0;
}

u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
{
	fsp_notify_f notify;
	struct fsp_notify_params params;
	struct fsp_notify_params *params_ptr;
	u32 status;

	if (!fsp_hdr)
		fsp_hdr = gd->arch.fsp_s_hdr;

	if (!fsp_hdr)
		return log_msg_ret("no FSP", -ENOENT);

	notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
	params.phase = phase;
	params_ptr = &params;

	/*
	 * Use ASM code to ensure correct parameter is on the stack for
	 * FspNotify as U-Boot is using different ABI from FSP
	 */
	asm volatile (
		"pushl	%1;"		/* push notify phase */
		"call	*%%eax;"	/* call FspNotify */
		"addl	$4, %%esp;"	/* clean up the stack */
		: "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
	);

	return status;
}