1// SPDX-License-Identifier: Intel
2/*
3 * Copyright 2019 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <init.h>
10#include <log.h>
11#include <spi_flash.h>
12#include <asm/fsp/fsp_support.h>
13#include <asm/fsp2/fsp_internal.h>
14#include <asm/global_data.h>
15
16/* The amount of the FSP header to probe to obtain what we need */
17#define PROBE_BUF_SIZE 0x180
18
19int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
20		   struct fsp_header **fspp)
21{
22	static efi_guid_t guid = FSP_HEADER_GUID;
23	struct fv_ext_header *exhdr;
24	struct fsp_header *fsp;
25	struct ffs_file_header *file_hdr;
26	struct fv_header *fv;
27	struct raw_section *raw;
28	void *ptr, *base;
29	u8 buf[PROBE_BUF_SIZE];
30	struct udevice *dev;
31	int ret;
32
33	/*
34	 * There are quite a very steps to work through all the headers in this
35	 * file and the structs have similar names. Turn on debugging if needed
36	 * to understand what is going wrong.
37	 *
38	 * You are in a maze of twisty little headers all alike.
39	 */
40	log_debug("offset=%x buf=%x, use_spi_flash=%d\n", (uint)offset,
41		  (uint)buf, use_spi_flash);
42	if (use_spi_flash) {
43		ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
44		if (ret)
45			return log_msg_ret("Cannot find flash device", ret);
46		ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
47		if (ret)
48			return log_msg_ret("Cannot read flash", ret);
49	} else {
50		memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
51	}
52
53	/* Initalise the FSP base */
54	ptr = buf;
55	fv = ptr;
56
57	/* Check the FV signature, _FVH */
58	log_debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
59	if (fv->sign != EFI_FVH_SIGNATURE)
60		return log_msg_ret("Base FV signature", -EINVAL);
61
62	/* Go to the end of the FV header and align the address */
63	log_debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
64	ptr += fv->ext_hdr_off;
65	exhdr = ptr;
66	ptr += ALIGN(exhdr->ext_hdr_size, 8);
67	log_debug("ptr=%x\n", ptr - (void *)buf);
68
69	/* Check the FFS GUID */
70	file_hdr = ptr;
71	if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
72		return log_msg_ret("Base FFS GUID", -ENXIO);
73	/* Add the FFS header size to find the raw section header */
74	ptr = file_hdr + 1;
75
76	raw = ptr;
77	log_debug("raw->type = %x\n", raw->type);
78	if (raw->type != EFI_SECTION_RAW)
79		return log_msg_ret("Section type not RAW", -ENOEXEC);
80
81	/* Add the raw section header size to find the FSP header */
82	ptr = raw + 1;
83	fsp = ptr;
84
85	/* Check the FSPH header */
86	log_debug("fsp %x, fsp-buf=%x, si=%x\n", (uint)fsp, ptr - (void *)buf,
87		  (void *)&fsp->fsp_silicon_init - (void *)buf);
88	if (fsp->sign != EFI_FSPH_SIGNATURE)
89		return log_msg_ret("Base FSPH signature", -EACCES);
90
91	base = (void *)fsp->img_base;
92	log_debug("image base %x\n", (uint)base);
93	if (fsp->fsp_mem_init)
94		log_debug("mem_init offset %x\n", (uint)fsp->fsp_mem_init);
95	else if (fsp->fsp_silicon_init)
96		log_debug("silicon_init offset %x\n",
97			  (uint)fsp->fsp_silicon_init);
98	if (use_spi_flash) {
99		ret = spi_flash_read_dm(dev, offset, size, base);
100		if (ret)
101			return log_msg_ret("Could not read FPS-M", ret);
102	} else {
103		memcpy(base, (void *)offset, size);
104	}
105	ptr = base + (ptr - (void *)buf);
106	*fspp = ptr;
107
108	return 0;
109}
110
111u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
112{
113	fsp_notify_f notify;
114	struct fsp_notify_params params;
115	struct fsp_notify_params *params_ptr;
116	u32 status;
117
118	if (!ll_boot_init())
119		return 0;
120
121	if (!fsp_hdr)
122		fsp_hdr = gd->arch.fsp_s_hdr;
123
124	if (!fsp_hdr)
125		return log_msg_ret("no FSP", -ENOENT);
126
127	notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
128	params.phase = phase;
129	params_ptr = &params;
130
131	/*
132	 * Use ASM code to ensure correct parameter is on the stack for
133	 * FspNotify as U-Boot is using different ABI from FSP
134	 */
135	asm volatile (
136		"pushl	%1;"		/* push notify phase */
137		"call	*%%eax;"	/* call FspNotify */
138		"addl	$4, %%esp;"	/* clean up the stack */
139		: "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
140	);
141
142	return status;
143}
144