1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
4 *
5 * @par Reference(s):
6 * - UEFI Platform Initialization Specification
7 * (https://uefi.org/specs/PI/1.8/index.html)
8 */
9
10 #include <assert.h>
11 #include <inttypes.h>
12 #include <string.h>
13 #include <tee_api_defines.h>
14 #include <trace.h>
15 #include <util.h>
16
17 #include <efi/hob.h>
18
create_hob(struct efi_hob_handoff_info_table * hob_table,uint16_t hob_type,uint16_t hob_length)19 static void *create_hob(struct efi_hob_handoff_info_table *hob_table,
20 uint16_t hob_type, uint16_t hob_length)
21 {
22 size_t free_mem_size = 0;
23 struct efi_hob_generic_header *new_hob = NULL;
24 struct efi_hob_generic_header *hob_end = NULL;
25
26 hob_length = ROUNDUP(hob_length, HOB_ALIGN);
27
28 assert(hob_table && hob_length);
29
30 free_mem_size = hob_table->efi_free_memory_top -
31 hob_table->efi_free_memory_bottom;
32
33 /*
34 * hob_length already including sizeof(efi_hob_generic_header).
35 * See the each export interface create_xxx_hob.
36 */
37 if (hob_length > free_mem_size)
38 return NULL;
39
40 new_hob = (void *)hob_table->efi_end_of_hob_list;
41 new_hob->hob_type = hob_type;
42 new_hob->hob_length = hob_length;
43 new_hob->reserved = 0;
44
45 hob_end = (void *)((vaddr_t)new_hob + hob_length);
46 hob_end->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST;
47 hob_end->hob_length = sizeof(struct efi_hob_generic_header);
48 hob_end->reserved = 0;
49
50 hob_table->efi_end_of_hob_list = (vaddr_t)hob_end;
51 hob_table->efi_free_memory_bottom = (vaddr_t)(hob_end + 1);
52
53 return new_hob;
54 }
55
56 struct efi_hob_handoff_info_table *
efi_create_hob_list(vaddr_t mem_begin,size_t mem_len,vaddr_t mem_free_begin,size_t mem_free_len)57 efi_create_hob_list(vaddr_t mem_begin, size_t mem_len,
58 vaddr_t mem_free_begin, size_t mem_free_len)
59 {
60 struct efi_hob_handoff_info_table *hob_table = NULL;
61 struct efi_hob_generic_header *hob_end = NULL;
62
63 if (!mem_begin || !mem_free_begin || !mem_len || !mem_free_len)
64 return NULL;
65
66 hob_table = (void *)mem_free_begin;
67 hob_end = (void *)(hob_table + 1);
68
69 hob_table->header.hob_type = EFI_HOB_TYPE_HANDOFF;
70 hob_table->header.hob_length =
71 sizeof(struct efi_hob_handoff_info_table);
72 hob_table->header.reserved = 0;
73
74 hob_end->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST;
75 hob_end->hob_length = sizeof(struct efi_hob_generic_header);
76 hob_end->reserved = 0;
77
78 hob_table->version = EFI_HOB_HANDOFF_TABLE_VERSION;
79 hob_table->boot_mode = BOOT_WITH_FULL_CONFIGURATION;
80
81 hob_table->efi_memory_top = (vaddr_t)(mem_begin + mem_len);
82 hob_table->efi_memory_bottom = (vaddr_t)mem_begin;
83 hob_table->efi_free_memory_top = (vaddr_t)mem_begin + mem_free_len;
84 hob_table->efi_free_memory_bottom = (vaddr_t)(hob_end + 1);
85 hob_table->efi_end_of_hob_list = (vaddr_t)hob_end;
86
87 return hob_table;
88 }
89
90 TEE_Result
efi_create_resource_desc_hob(struct efi_hob_handoff_info_table * hob_table,efi_resource_type_t resource_type,efi_resource_attribute_type_t resource_attribute,efi_physical_address_t phy_addr_start,uint64_t resource_length)91 efi_create_resource_desc_hob(struct efi_hob_handoff_info_table *hob_table,
92 efi_resource_type_t resource_type,
93 efi_resource_attribute_type_t resource_attribute,
94 efi_physical_address_t phy_addr_start,
95 uint64_t resource_length)
96 {
97 struct efi_hob_resource_descriptor *rd_hop = NULL;
98
99 rd_hop = create_hob(hob_table, EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
100 sizeof(struct efi_hob_resource_descriptor));
101
102 if (!rd_hop)
103 return TEE_ERROR_OUT_OF_MEMORY;
104
105 rd_hop->resource_type = resource_type;
106 rd_hop->resource_attribute = resource_attribute;
107 rd_hop->physical_start = phy_addr_start;
108 rd_hop->resource_length = resource_length;
109 memset(&rd_hop->owner, 0, sizeof(TEE_UUID));
110
111 return TEE_SUCCESS;
112 }
113
efi_create_guid_hob(struct efi_hob_handoff_info_table * hob_table,TEE_UUID * guid,uint16_t data_length,void ** data)114 TEE_Result efi_create_guid_hob(struct efi_hob_handoff_info_table *hob_table,
115 TEE_UUID *guid, uint16_t data_length,
116 void **data)
117 {
118 struct efi_hob_guid_type *guid_hob = NULL;
119 uint16_t hob_length = 0;
120
121 hob_length = data_length + sizeof(struct efi_hob_guid_type);
122
123 if (!guid || !data || hob_length < data_length)
124 return TEE_ERROR_BAD_PARAMETERS;
125
126 guid_hob = create_hob(hob_table,
127 EFI_HOB_TYPE_GUID_EXTENSION, hob_length);
128 if (!guid_hob) {
129 *data = NULL;
130
131 return TEE_ERROR_OUT_OF_MEMORY;
132 }
133
134 memcpy(&guid_hob->name, guid, sizeof(TEE_UUID));
135
136 *data = (void *)(guid_hob + 1);
137
138 return TEE_SUCCESS;
139 }
140
efi_create_fv_hob(struct efi_hob_handoff_info_table * hob_table,efi_physical_address_t base_addr,uint64_t size)141 TEE_Result efi_create_fv_hob(struct efi_hob_handoff_info_table *hob_table,
142 efi_physical_address_t base_addr, uint64_t size)
143 {
144 struct efi_hob_firmware_volume *fv_hob = NULL;
145
146 fv_hob = create_hob(hob_table, EFI_HOB_TYPE_FV,
147 sizeof(struct efi_hob_firmware_volume));
148 if (!fv_hob)
149 return TEE_ERROR_OUT_OF_MEMORY;
150
151 fv_hob->base_address = base_addr;
152 fv_hob->length = size;
153
154 return TEE_SUCCESS;
155 }
156