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