]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - arch/x86/cpu/queensbay/fsp_support.c
x86: Use consistent name XXX_ADDR for binary blob flash address
[karo-tx-uboot.git] / arch / x86 / cpu / queensbay / fsp_support.c
1 /*
2  * Copyright (C) 2013, Intel Corporation
3  * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
4  *
5  * SPDX-License-Identifier:     Intel
6  */
7
8 #include <common.h>
9 #include <asm/arch/fsp/fsp_support.h>
10 #include <asm/post.h>
11
12 /**
13  * Reads a 64-bit value from memory that may be unaligned.
14  *
15  * This function returns the 64-bit value pointed to by buf. The function
16  * guarantees that the read operation does not produce an alignment fault.
17  *
18  * If the buf is NULL, then ASSERT().
19  *
20  * @buf: Pointer to a 64-bit value that may be unaligned.
21  *
22  * @return: The 64-bit value read from buf.
23  */
24 static u64 read_unaligned64(const u64 *buf)
25 {
26         ASSERT(buf != NULL);
27
28         return *buf;
29 }
30
31 /**
32  * Compares two GUIDs
33  *
34  * If the GUIDs are identical then TRUE is returned.
35  * If there are any bit differences in the two GUIDs, then FALSE is returned.
36  *
37  * If guid1 is NULL, then ASSERT().
38  * If guid2 is NULL, then ASSERT().
39  *
40  * @guid1:        A pointer to a 128 bit GUID.
41  * @guid2:        A pointer to a 128 bit GUID.
42  *
43  * @retval TRUE:  guid1 and guid2 are identical.
44  * @retval FALSE: guid1 and guid2 are not identical.
45  */
46 static unsigned char compare_guid(const struct efi_guid_t *guid1,
47                                   const struct efi_guid_t *guid2)
48 {
49         u64 guid1_low;
50         u64 guid2_low;
51         u64 guid1_high;
52         u64 guid2_high;
53
54         guid1_low  = read_unaligned64((const u64 *)guid1);
55         guid2_low  = read_unaligned64((const u64 *)guid2);
56         guid1_high = read_unaligned64((const u64 *)guid1 + 1);
57         guid2_high = read_unaligned64((const u64 *)guid2 + 1);
58
59         return (unsigned char)(guid1_low == guid2_low && guid1_high == guid2_high);
60 }
61
62 u32 __attribute__((optimize("O0"))) find_fsp_header(void)
63 {
64         volatile register u8 *fsp asm("eax");
65
66         /* Initalize the FSP base */
67         fsp = (u8 *)CONFIG_FSP_ADDR;
68
69         /* Check the FV signature, _FVH */
70         if (((struct fv_header_t *)fsp)->sign == 0x4856465F) {
71                 /* Go to the end of the FV header and align the address */
72                 fsp += ((struct fv_header_t *)fsp)->ext_hdr_off;
73                 fsp += ((struct fv_ext_header_t *)fsp)->ext_hdr_size;
74                 fsp  = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8);
75         } else {
76                 fsp  = 0;
77         }
78
79         /* Check the FFS GUID */
80         if (fsp &&
81             (((u32 *)&(((struct ffs_file_header_t *)fsp)->name))[0] == 0x912740BE) &&
82             (((u32 *)&(((struct ffs_file_header_t *)fsp)->name))[1] == 0x47342284) &&
83             (((u32 *)&(((struct ffs_file_header_t *)fsp)->name))[2] == 0xB08471B9) &&
84             (((u32 *)&(((struct ffs_file_header_t *)fsp)->name))[3] == 0x0C3F3527)) {
85                 /* Add the FFS header size to find the raw section header */
86                 fsp += sizeof(struct ffs_file_header_t);
87         } else {
88                 fsp = 0;
89         }
90
91         if (fsp &&
92             ((struct raw_section_t *)fsp)->type == EFI_SECTION_RAW) {
93                 /* Add the raw section header size to find the FSP header */
94                 fsp += sizeof(struct raw_section_t);
95         } else {
96                 fsp = 0;
97         }
98
99         return (u32)fsp;
100 }
101
102 void fsp_continue(struct shared_data_t *shared_data, u32 status, void *hob_list)
103 {
104         u32 stack_len;
105         u32 stack_base;
106         u32 stack_top;
107
108         post_code(POST_MRC);
109
110         ASSERT(status == 0);
111
112         /* Get the migrated stack in normal memory */
113         stack_base = (u32)get_bootloader_tmp_mem(hob_list, &stack_len);
114         ASSERT(stack_base != 0);
115         stack_top  = stack_base + stack_len - sizeof(u32);
116
117         /*
118          * Old stack base is stored at the very end of the stack top,
119          * use it to calculate the migrated shared data base
120          */
121         shared_data = (struct shared_data_t *)(stack_base +
122                         ((u32)shared_data - *(u32 *)stack_top));
123
124         /* The boot loader main function entry */
125         fsp_init_done(hob_list);
126 }
127
128 void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
129 {
130         struct shared_data_t shared_data;
131         fsp_init_f init;
132         struct fsp_init_params_t params;
133         struct fspinit_rtbuf_t rt_buf;
134         struct vpd_region_t *fsp_vpd;
135         struct fsp_header_t *fsp_hdr;
136         struct fsp_init_params_t *params_ptr;
137         struct upd_region_t *fsp_upd;
138
139         fsp_hdr = (struct fsp_header_t *)find_fsp_header();
140         if (fsp_hdr == NULL) {
141                 /* No valid FSP info header was found */
142                 ASSERT(FALSE);
143         }
144
145         fsp_upd = (struct upd_region_t *)&shared_data.fsp_upd;
146         memset((void *)&rt_buf, 0, sizeof(struct fspinit_rtbuf_t));
147
148         /* Reserve a gap in stack top */
149         rt_buf.common.stack_top = (u32 *)stack_top - 32;
150         rt_buf.common.boot_mode = boot_mode;
151         rt_buf.common.upd_data = (struct upd_region_t *)fsp_upd;
152
153         /* Get VPD region start */
154         fsp_vpd = (struct vpd_region_t *)(fsp_hdr->img_base +
155                         fsp_hdr->cfg_region_off);
156
157         /* Verifify the VPD data region is valid */
158         ASSERT((fsp_vpd->img_rev == VPD_IMAGE_REV) &&
159                (fsp_vpd->sign == VPD_IMAGE_ID));
160
161         /* Copy default data from Flash */
162         memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset),
163                sizeof(struct upd_region_t));
164
165         /* Verifify the UPD data region is valid */
166         ASSERT(fsp_upd->terminator == 0x55AA);
167
168         /* Override any UPD setting if required */
169         update_fsp_upd(fsp_upd);
170
171         memset((void *)&params, 0, sizeof(struct fsp_init_params_t));
172         params.nvs_buf = nvs_buf;
173         params.rt_buf = (struct fspinit_rtbuf_t *)&rt_buf;
174         params.continuation = (fsp_continuation_f)asm_continuation;
175
176         init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init);
177         params_ptr = &params;
178
179         shared_data.fsp_hdr = fsp_hdr;
180         shared_data.stack_top = (u32 *)stack_top;
181
182         post_code(POST_PRE_MRC);
183
184         /*
185          * Use ASM code to ensure the register value in EAX & ECX
186          * will be passed into BlContinuationFunc
187          */
188         asm volatile (
189                 "pushl  %0;"
190                 "call   *%%eax;"
191                 ".global asm_continuation;"
192                 "asm_continuation:;"
193                 "movl   %%ebx, %%eax;"          /* shared_data */
194                 "movl   4(%%esp), %%edx;"       /* status */
195                 "movl   8(%%esp), %%ecx;"       /* hob_list */
196                 "jmp    fsp_continue;"
197                 : : "m"(params_ptr), "a"(init), "b"(&shared_data)
198         );
199
200         /*
201          * Should never get here.
202          * Control will continue from romstage_main_continue_asm.
203          * This line below is to prevent the compiler from optimizing
204          * structure intialization.
205          */
206         init(&params);
207
208         /*
209          * Should never return.
210          * Control will continue from ContinuationFunc
211          */
212         ASSERT(FALSE);
213 }
214
215 u32 fsp_notify(struct fsp_header_t *fsp_hdr, u32 phase)
216 {
217         fsp_notify_f notify;
218         struct fsp_notify_params_t params;
219         struct fsp_notify_params_t *params_ptr;
220         u32 status;
221
222         if (!fsp_hdr)
223                 fsp_hdr = (struct fsp_header_t *)find_fsp_header();
224
225         if (fsp_hdr == NULL) {
226                 /* No valid FSP info header */
227                 ASSERT(FALSE);
228         }
229
230         notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
231         params.phase = phase;
232         params_ptr = &params;
233
234         /*
235          * Use ASM code to ensure correct parameter is on the stack for
236          * FspNotify as U-Boot is using different ABI from FSP
237          */
238         asm volatile (
239                 "pushl  %1;"            /* push notify phase */
240                 "call   *%%eax;"        /* call FspNotify */
241                 "addl   $4, %%esp;"     /* clean up the stack */
242                 : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
243         );
244
245         return status;
246 }
247
248 u32 get_usable_lowmem_top(const void *hob_list)
249 {
250         union hob_pointers_t hob;
251         phys_addr_t phys_start;
252         u32 top;
253
254         /* Get the HOB list for processing */
255         hob.raw = (void *)hob_list;
256
257         /* * Collect memory ranges */
258         top = 0x100000;
259         while (!END_OF_HOB(hob)) {
260                 if (hob.hdr->type == HOB_TYPE_RES_DESC) {
261                         if (hob.res_desc->type == RES_SYS_MEM) {
262                                 phys_start = hob.res_desc->phys_start;
263                                 /* Need memory above 1MB to be collected here */
264                                 if (phys_start >= 0x100000 &&
265                                     phys_start < (phys_addr_t)0x100000000)
266                                         top += (u32)(hob.res_desc->len);
267                         }
268                 }
269                 hob.raw = GET_NEXT_HOB(hob);
270         }
271
272         return top;
273 }
274
275 u64 get_usable_highmem_top(const void *hob_list)
276 {
277         union hob_pointers_t hob;
278         phys_addr_t phys_start;
279         u64 top;
280
281         /* Get the HOB list for processing */
282         hob.raw = (void *)hob_list;
283
284         /* Collect memory ranges */
285         top = 0x100000000;
286         while (!END_OF_HOB(hob)) {
287                 if (hob.hdr->type == HOB_TYPE_RES_DESC) {
288                         if (hob.res_desc->type == RES_SYS_MEM) {
289                                 phys_start = hob.res_desc->phys_start;
290                                 /* Need memory above 1MB to be collected here */
291                                 if (phys_start >= (phys_addr_t)0x100000000)
292                                         top += (u32)(hob.res_desc->len);
293                         }
294                 }
295                 hob.raw = GET_NEXT_HOB(hob);
296         }
297
298         return top;
299 }
300
301 u64 get_fsp_reserved_mem_from_guid(const void *hob_list, u64 *len,
302                                    struct efi_guid_t *guid)
303 {
304         union hob_pointers_t hob;
305
306         /* Get the HOB list for processing */
307         hob.raw = (void *)hob_list;
308
309         /* Collect memory ranges */
310         while (!END_OF_HOB(hob)) {
311                 if (hob.hdr->type == HOB_TYPE_RES_DESC) {
312                         if (hob.res_desc->type == RES_MEM_RESERVED) {
313                                 if (compare_guid(&hob.res_desc->owner, guid)) {
314                                         if (len)
315                                                 *len = (u32)(hob.res_desc->len);
316
317                                         return (u64)(hob.res_desc->phys_start);
318                                 }
319                         }
320                 }
321                 hob.raw = GET_NEXT_HOB(hob);
322         }
323
324         return 0;
325 }
326
327 u32 get_fsp_reserved_mem(const void *hob_list, u32 *len)
328 {
329         const struct efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
330         u64 length;
331         u32 base;
332
333         base = (u32)get_fsp_reserved_mem_from_guid(hob_list,
334                         &length, (struct efi_guid_t *)&guid);
335         if ((len != 0) && (base != 0))
336                 *len = (u32)length;
337
338         return base;
339 }
340
341 u32 get_tseg_reserved_mem(const void *hob_list, u32 *len)
342 {
343         const struct efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID;
344         u64 length;
345         u32 base;
346
347         base = (u32)get_fsp_reserved_mem_from_guid(hob_list,
348                         &length, (struct efi_guid_t *)&guid);
349         if ((len != 0) && (base != 0))
350                 *len = (u32)length;
351
352         return base;
353 }
354
355 void *get_next_hob(u16 type, const void *hob_list)
356 {
357         union hob_pointers_t hob;
358
359         ASSERT(hob_list != NULL);
360
361         hob.raw = (u8 *)hob_list;
362
363         /* Parse the HOB list until end of list or matching type is found */
364         while (!END_OF_HOB(hob)) {
365                 if (hob.hdr->type == type)
366                         return hob.raw;
367
368                 hob.raw = GET_NEXT_HOB(hob);
369         }
370
371         return NULL;
372 }
373
374 void *get_next_guid_hob(const struct efi_guid_t *guid, const void *hob_list)
375 {
376         union hob_pointers_t hob;
377
378         hob.raw = (u8 *)hob_list;
379         while ((hob.raw = get_next_hob(HOB_TYPE_GUID_EXT,
380                         hob.raw)) != NULL) {
381                 if (compare_guid(guid, &hob.guid->name))
382                         break;
383                 hob.raw = GET_NEXT_HOB(hob);
384         }
385
386         return hob.raw;
387 }
388
389 void *get_guid_hob_data(const void *hob_list, u32 *len, struct efi_guid_t *guid)
390 {
391         u8 *guid_hob;
392
393         guid_hob = get_next_guid_hob(guid, hob_list);
394         if (guid_hob == NULL) {
395                 return NULL;
396         } else {
397                 if (len)
398                         *len = GET_GUID_HOB_DATA_SIZE(guid_hob);
399
400                 return GET_GUID_HOB_DATA(guid_hob);
401         }
402 }
403
404 void *get_fsp_nvs_data(const void *hob_list, u32 *len)
405 {
406         const struct efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
407
408         return get_guid_hob_data(hob_list, len, (struct efi_guid_t *)&guid);
409 }
410
411 void *get_bootloader_tmp_mem(const void *hob_list, u32 *len)
412 {
413         const struct efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
414
415         return get_guid_hob_data(hob_list, len, (struct efi_guid_t *)&guid);
416 }