summaryrefslogtreecommitdiffstats
path: root/arch/x86/lib/fsp1/fsp_support.c
blob: c7a2c73846b4bea4036b68a3bb323b7fc1462d7c (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// SPDX-License-Identifier: Intel
/*
 * Copyright (C) 2013, Intel Corporation
 * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
 */

#include <common.h>
#include <asm/fsp1/fsp_support.h>
#include <asm/post.h>

struct fsp_header *__attribute__((optimize("O0"))) fsp_find_header(void)
{
	/*
	 * This function may be called before the a stack is established,
	 * so special care must be taken. First, it cannot declare any local
	 * variable using stack. Only register variable can be used here.
	 * Secondly, some compiler version will add prolog or epilog code
	 * for the C function. If so the function call may not work before
	 * stack is ready.
	 *
	 * GCC 4.8.1 has been verified to be working for the following codes.
	 */
	volatile register u8 *fsp asm("eax");

	/* Initalize the FSP base */
	fsp = (u8 *)CONFIG_FSP_ADDR;

	/* Check the FV signature, _FVH */
	if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) {
		/* Go to the end of the FV header and align the address */
		fsp += ((struct fv_header *)fsp)->ext_hdr_off;
		fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size;
		fsp  = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8);
	} else {
		fsp  = 0;
	}

	/* Check the FFS GUID */
	if (fsp &&
	    ((struct ffs_file_header *)fsp)->name.b[0] == FSP_GUID_BYTE0 &&
	    ((struct ffs_file_header *)fsp)->name.b[1] == FSP_GUID_BYTE1 &&
	    ((struct ffs_file_header *)fsp)->name.b[2] == FSP_GUID_BYTE2 &&
	    ((struct ffs_file_header *)fsp)->name.b[3] == FSP_GUID_BYTE3 &&
	    ((struct ffs_file_header *)fsp)->name.b[4] == FSP_GUID_BYTE4 &&
	    ((struct ffs_file_header *)fsp)->name.b[5] == FSP_GUID_BYTE5 &&
	    ((struct ffs_file_header *)fsp)->name.b[6] == FSP_GUID_BYTE6 &&
	    ((struct ffs_file_header *)fsp)->name.b[7] == FSP_GUID_BYTE7 &&
	    ((struct ffs_file_header *)fsp)->name.b[8] == FSP_GUID_BYTE8 &&
	    ((struct ffs_file_header *)fsp)->name.b[9] == FSP_GUID_BYTE9 &&
	    ((struct ffs_file_header *)fsp)->name.b[10] == FSP_GUID_BYTE10 &&
	    ((struct ffs_file_header *)fsp)->name.b[11] == FSP_GUID_BYTE11 &&
	    ((struct ffs_file_header *)fsp)->name.b[12] == FSP_GUID_BYTE12 &&
	    ((struct ffs_file_header *)fsp)->name.b[13] == FSP_GUID_BYTE13 &&
	    ((struct ffs_file_header *)fsp)->name.b[14] == FSP_GUID_BYTE14 &&
	    ((struct ffs_file_header *)fsp)->name.b[15] == FSP_GUID_BYTE15) {
		/* Add the FFS header size to find the raw section header */
		fsp += sizeof(struct ffs_file_header);
	} else {
		fsp = 0;
	}

	if (fsp &&
	    ((struct raw_section *)fsp)->type == EFI_SECTION_RAW) {
		/* Add the raw section header size to find the FSP header */
		fsp += sizeof(struct raw_section);
	} else {
		fsp = 0;
	}

	return (struct fsp_header *)fsp;
}

void fsp_continue(u32 status, void *hob_list)
{
	post_code(POST_MRC);

	assert(status == 0);

	/* The boot loader main function entry */
	fsp_init_done(hob_list);
}

void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
{
	struct fsp_config_data config_data;
	fsp_init_f init;
	struct fsp_init_params params;
	struct fspinit_rtbuf rt_buf;
	struct fsp_header *fsp_hdr;
	struct fsp_init_params *params_ptr;
#ifdef CONFIG_FSP_USE_UPD
	struct vpd_region *fsp_vpd;
	struct upd_region *fsp_upd;
#endif

	fsp_hdr = fsp_find_header();
	if (fsp_hdr == NULL) {
		/* No valid FSP info header was found */
		panic("Invalid FSP header");
	}

	config_data.common.fsp_hdr = fsp_hdr;
	config_data.common.stack_top = stack_top;
	config_data.common.boot_mode = boot_mode;

#ifdef CONFIG_FSP_USE_UPD
	/* Get VPD region start */
	fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base +
			fsp_hdr->cfg_region_off);

	/* Verify the VPD data region is valid */
	assert(fsp_vpd->sign == VPD_IMAGE_ID);

	fsp_upd = &config_data.fsp_upd;

	/* Copy default data from Flash */
	memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset),
	       sizeof(struct upd_region));

	/* Verify the UPD data region is valid */
	assert(fsp_upd->terminator == UPD_TERMINATOR);
#endif

	memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf));

	/* Override any configuration if required */
	fsp_update_configs(&config_data, &rt_buf);

	memset(&params, 0, sizeof(struct fsp_init_params));
	params.nvs_buf = nvs_buf;
	params.rt_buf = (struct fspinit_rtbuf *)&rt_buf;
	params.continuation = (fsp_continuation_f)fsp_asm_continuation;

	init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init);
	params_ptr = &params;

	post_code(POST_PRE_MRC);

	/* Load GDT for FSP */
	setup_fsp_gdt();

	/*
	 * Use ASM code to ensure the register value in EAX & EDX
	 * will be passed into fsp_continue
	 */
	asm volatile (
		"pushl	%0;"
		"call	*%%eax;"
		".global fsp_asm_continuation;"
		"fsp_asm_continuation:;"
		"movl	4(%%esp), %%eax;"	/* status */
		"movl	8(%%esp), %%edx;"	/* hob_list */
		"jmp	fsp_continue;"
		: : "m"(params_ptr), "a"(init)
	);

	/*
	 * Should never get here.
	 * Control will continue from fsp_continue.
	 * This line below is to prevent the compiler from optimizing
	 * structure intialization.
	 *
	 * DO NOT REMOVE!
	 */
	init(&params);
}

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 = (struct fsp_header *)fsp_find_header();

	if (fsp_hdr == NULL) {
		/* No valid FSP info header */
		panic("Invalid FSP header");
	}

	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;
}