1 /*
2  * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef VARIABLE_INDEX_H
9 #define VARIABLE_INDEX_H
10 
11 #include <protocols/common/efi/efi_status.h>
12 #include <protocols/common/efi/efi_types.h>
13 #include <protocols/service/smm_variable/smm_variable_proto.h>
14 #include <stdbool.h>
15 #include <stddef.h>
16 #include <stdint.h>
17 
18 #include "variable_checker.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**
25  * Implementation limits
26  */
27 #define VARIABLE_INDEX_MAX_NAME_SIZE (64)
28 #define FINGERPRINT_SIZE             (32)
29 
30 /**
31  * \brief variable_metadata structure definition
32  *
33  * Holds metadata associated with stored variable.
34  */
35 struct variable_metadata {
36 	EFI_GUID guid;
37 	EFI_TIME timestamp;
38 	uint8_t fingerprint[FINGERPRINT_SIZE];
39 	size_t name_size;
40 	int16_t name[VARIABLE_INDEX_MAX_NAME_SIZE];
41 	uint32_t attributes;
42 	uint64_t uid;
43 };
44 
45 /**
46  * \brief variable_info structure definition
47  *
48  * Holds information about a stored variable.
49  */
50 struct variable_info {
51 	struct variable_metadata metadata;
52 	struct variable_constraints check_constraints;
53 
54 	bool is_variable_set;
55 	bool is_constraints_set;
56 };
57 
58 /**
59  * \brief An entry in the index
60  *
61  * Represents a store variable in the variable index.
62  */
63 struct variable_entry {
64 	struct variable_info info;
65 
66 	bool in_use;
67 	bool dirty;
68 };
69 
70 /**
71  * \brief variable_index structure definition
72  *
73  * Provides an index of stored variables to allow the uefi variable store
74  * contents to be enumerated.
75  */
76 struct variable_index {
77 	size_t max_variables;
78 	uint32_t counter;
79 	struct variable_entry *entries;
80 };
81 
82 /**
83  * @brief      Initialises a variable_index
84  *
85  * @param[in]  context variable_index
86  * @param[in]  max_variables The maximum number of stored variables
87  *
88  * @return     EFI_SUCCESS if initialized successfully
89  */
90 efi_status_t variable_index_init(struct variable_index *context, size_t max_variables);
91 
92 /**
93  * @brief      De-initialises a variable_index
94  *
95  * @param[in]  context variable_index
96  */
97 void variable_index_deinit(struct variable_index *context);
98 
99 /**
100  * @brief      Returns the maximum dump size
101  *
102  * For a given maximum index size, returns the size of the
103  * buffer that is needed to hold all serialized variable_info
104  * objects.
105  *
106  * @param[in]  context variable_index
107  */
108 size_t variable_index_max_dump_size(struct variable_index *context);
109 
110 /**
111  * @brief      Find info about a variable
112  *
113  * @param[in]  context variable_index
114  * @param[in]  guid The variable's guid
115  * @param[in]  name_size The name parameter's size
116  * @param[in]  name The variable's name
117  *
118  * @return     Pointer to variable_info or NULL
119  */
120 struct variable_info *variable_index_find(const struct variable_index *context,
121 					  const EFI_GUID *guid, size_t name_size,
122 					  const int16_t *name);
123 
124 /**
125  * @brief      Find the next variable in the index
126  *
127  * @param[in]  context variable_index
128  * @param[in]  guid The variable's guid
129  * @param[in]  name_size The name parameter's size
130  * @param[in]  name The variable's name
131  * @param[out] status Provides error status
132  *
133  * @return     Pointer to variable_info or NULL
134  */
135 struct variable_info *variable_index_find_next(const struct variable_index *context,
136 					       const EFI_GUID *guid, size_t name_size,
137 					       const int16_t *name, efi_status_t *status);
138 
139 /**
140  * @brief      Add a new entry to the index
141  *
142  * An entry is needed either when a new variable is created or
143  * when variable constraints are set for a variable that doesn't
144  * yet exist.
145  *
146  * @param[in]  context variable_index
147  * @param[in]  guid The variable's guid
148  * @param[in]  name_size The name parameter's size
149  * @param[in]  name The variable's name
150  *
151  * @return     Pointer to variable_info or NULL
152  */
153 struct variable_info *variable_index_add_entry(const struct variable_index *context,
154 					       const EFI_GUID *guid, size_t name_size,
155 					       const int16_t *name);
156 
157 /**
158  * @brief      Remove an unused entry from the index
159  *
160  * Removes an entry if it is not in use.
161  *
162  * @param[in]  context variable_index
163  * @param[in]  info The variable info corresponding to the entry to remove
164  */
165 void variable_index_remove_unused_entry(const struct variable_index *context,
166 					struct variable_info *info);
167 
168 /**
169  * @brief      Set a variable to the index
170  *
171  * An entry for the variable must already exist.
172  *
173  * @param[in]  info variable info
174  * @param[in]  attributes The variable's attributes
175  */
176 void variable_index_set_variable(struct variable_info *info, uint32_t attributes);
177 
178 /**
179  * @brief      Clear a variable from the index
180  *
181  * Clears a variable from the index
182  *
183  * @param[in]  context variable_index
184  * @param[in]  info The variable info corresponding to the variable to clear
185  */
186 void variable_index_clear_variable(const struct variable_index *context,
187 				   struct variable_info *info);
188 
189 /**
190  * @brief      Set a check constraints object associated with a variavle
191  *
192  * @param[in]  info variable info
193  * @param[in]  constraints The check constraints
194  */
195 void variable_index_set_constraints(struct variable_info *info,
196 				    const struct variable_constraints *constraints);
197 
198 /**
199  * @brief      Dump the serialized index contents for persistent backup
200  *
201  * @param[in]  context variable_index
202  * @param[in]  buffer_size Size of destination buffer
203  * @param[in]  buffer Dump to this buffer
204  * @param[out] data_len Length of serialized data
205  * @param[out] any_dirty True if there is unsaved data
206  *
207  * @return     EFI_SUCCESS if all the changes are dumped successfully
208  */
209 efi_status_t variable_index_dump(const struct variable_index *context, size_t buffer_size,
210 				 uint8_t *buffer, size_t *data_len, bool *any_dirty);
211 
212 /**
213  * @brief     Confirms the successful write of the variable index into the storage
214  *            by stepping the counter.
215  *
216  * @param[in] context variable_index
217  */
218 void variable_index_confirm_write(struct variable_index *context);
219 
220 /**
221  * @brief      Restore the serialized index contents
222  *
223  * Should be called straight after the variable index is initialized to
224  * restore any NV variable info from persistent storage.
225  *
226  * @param[in]  context variable_index
227  * @param[in]  data_len The length of the data to load
228  * @param[in]  buffer Load from this buffer
229  *
230  * @return     Number of bytes loaded
231  */
232 size_t variable_index_restore(struct variable_index *context, size_t data_len,
233 			      const uint8_t *buffer);
234 
235 #ifdef __cplusplus
236 }
237 #endif
238 
239 #endif /* VARIABLE_INDEX_H */
240