/src/nsmd/libnsm/firmware-utils.c
Line | Count | Source |
1 | | /* |
2 | | * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & |
3 | | * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 |
4 | | * |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | * |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | #include "firmware-utils.h" |
19 | | |
20 | | #include <endian.h> |
21 | | #include <stdio.h> |
22 | | #include <string.h> |
23 | | |
24 | | #define DBG1(x) |
25 | | #define DBG2(x) |
26 | | #define DBGW(x) |
27 | 0 | #define DBGE(x) x |
28 | | |
29 | | struct nsm_firmware_aggregate_tag { |
30 | | uint8_t tag; |
31 | | uint8_t valid : 1; |
32 | | uint8_t length : 3; |
33 | | uint8_t reserved : 4; |
34 | | uint8_t data[1]; |
35 | | } __attribute__((packed)); |
36 | | |
37 | | void printArrayAsHex(const uint8_t *array, size_t size) |
38 | 0 | { |
39 | 0 | for (size_t i = 0; i < size; ++i) { |
40 | 0 | printf("%02X ", array[i]); |
41 | 0 | } |
42 | 0 | printf("\n"); |
43 | 0 | } |
44 | | |
45 | | void encode_nsm_firmware_aggregate_tag_uint8(uint8_t **buffer, uint8_t tag, |
46 | | uint8_t value, |
47 | | uint16_t *buffer_size) |
48 | 0 | { |
49 | 0 | struct nsm_firmware_aggregate_tag *field = |
50 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
51 | 0 | field->tag = tag; |
52 | 0 | field->valid = 1; |
53 | 0 | field->length = 0; |
54 | 0 | field->reserved = 0; |
55 | 0 | field->data[0] = value; |
56 | 0 | *buffer += |
57 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint8_t) - 1; |
58 | 0 | *buffer_size += |
59 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint8_t) - 1; |
60 | 0 | } |
61 | | |
62 | | void encode_nsm_firmware_aggregate_tag_uint16(uint8_t **buffer, uint8_t tag, |
63 | | uint16_t value, |
64 | | uint16_t *buffer_size) |
65 | 0 | { |
66 | 0 | struct nsm_firmware_aggregate_tag *field = |
67 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
68 | 0 | field->tag = tag; |
69 | 0 | field->valid = 1; |
70 | 0 | field->length = 1; |
71 | 0 | field->reserved = 0; |
72 | 0 | value = htole16(value); |
73 | 0 | memcpy(field->data, &value, sizeof(uint16_t)); |
74 | 0 | *buffer += |
75 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint16_t) - 1; |
76 | 0 | *buffer_size += |
77 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint16_t) - 1; |
78 | 0 | } |
79 | | |
80 | | void encode_nsm_firmware_aggregate_tag_uint32(uint8_t **buffer, uint8_t tag, |
81 | | uint32_t value, |
82 | | uint16_t *buffer_size) |
83 | 0 | { |
84 | 0 | struct nsm_firmware_aggregate_tag *field = |
85 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
86 | 0 | field->tag = tag; |
87 | 0 | field->valid = 1; |
88 | 0 | field->length = 2; |
89 | 0 | field->reserved = 0; |
90 | 0 | value = htole32(value); |
91 | 0 | memcpy(field->data, &value, sizeof(uint32_t)); |
92 | 0 | *buffer += |
93 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint32_t) - 1; |
94 | 0 | *buffer_size += |
95 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint32_t) - 1; |
96 | 0 | } |
97 | | |
98 | | void encode_nsm_firmware_aggregate_tag_uint64(uint8_t **buffer, uint8_t tag, |
99 | | uint64_t value, |
100 | | uint16_t *buffer_size) |
101 | 0 | { |
102 | 0 | struct nsm_firmware_aggregate_tag *field = |
103 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
104 | 0 | field->tag = tag; |
105 | 0 | field->valid = 1; |
106 | 0 | field->length = 3; |
107 | 0 | field->reserved = 0; |
108 | 0 | value = htole64(value); |
109 | 0 | memcpy(field->data, &value, sizeof(uint64_t)); |
110 | 0 | *buffer += |
111 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint64_t) - 1; |
112 | 0 | *buffer_size += |
113 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint64_t) - 1; |
114 | 0 | } |
115 | | |
116 | | void encode_nsm_firmware_aggregate_tag_uint8_array(uint8_t **buffer, |
117 | | uint8_t tag, uint8_t *value, |
118 | | uint16_t *buffer_size) |
119 | 0 | { |
120 | 0 | struct nsm_firmware_aggregate_tag *field = |
121 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
122 | 0 | field->tag = tag; |
123 | 0 | field->valid = 1; |
124 | 0 | field->length = 4; |
125 | 0 | field->reserved = 0; |
126 | 0 | memcpy(field->data, value, 16); |
127 | 0 | *buffer += sizeof(struct nsm_firmware_aggregate_tag) + 16 - 1; |
128 | 0 | *buffer_size += sizeof(struct nsm_firmware_aggregate_tag) + 16 - 1; |
129 | 0 | } |
130 | | |
131 | | bool decode_nsm_firmware_aggregate_tag_uint8(uint8_t **buffer, uint8_t *tag, |
132 | | uint8_t *valid, uint8_t *value, |
133 | | uint16_t *buffer_size) |
134 | 0 | { |
135 | 0 | if (*buffer_size < |
136 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint8_t) - 1) { |
137 | 0 | return false; |
138 | 0 | } |
139 | 0 | struct nsm_firmware_aggregate_tag *field = |
140 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
141 | 0 | *tag = field->tag; |
142 | 0 | *valid = field->valid; |
143 | 0 | if (field->valid) { |
144 | 0 | *value = field->data[0]; |
145 | 0 | } |
146 | 0 | *buffer += |
147 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint8_t) - 1; |
148 | 0 | *buffer_size -= |
149 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint8_t) - 1; |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | | bool decode_nsm_firmware_aggregate_tag_uint16(uint8_t **buffer, uint8_t *tag, |
154 | | uint8_t *valid, uint16_t *value, |
155 | | uint16_t *buffer_size) |
156 | 0 | { |
157 | 0 | if (*buffer_size < |
158 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint16_t) - 1) { |
159 | 0 | return false; |
160 | 0 | } |
161 | 0 | struct nsm_firmware_aggregate_tag *field = |
162 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
163 | 0 | *tag = field->tag; |
164 | 0 | *valid = field->valid; |
165 | 0 | if (field->valid) { |
166 | 0 | memcpy(value, field->data, sizeof(uint16_t)); |
167 | 0 | *value = le16toh(*value); |
168 | 0 | } |
169 | 0 | *buffer += |
170 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint16_t) - 1; |
171 | 0 | *buffer_size -= |
172 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint16_t) - 1; |
173 | 0 | return true; |
174 | 0 | } |
175 | | |
176 | | bool decode_nsm_firmware_aggregate_tag_uint32(uint8_t **buffer, uint8_t *tag, |
177 | | uint8_t *valid, uint32_t *value, |
178 | | uint16_t *buffer_size) |
179 | 0 | { |
180 | 0 | if (*buffer_size < |
181 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint32_t) - 1) { |
182 | 0 | return false; |
183 | 0 | } |
184 | 0 | struct nsm_firmware_aggregate_tag *field = |
185 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
186 | 0 | *tag = field->tag; |
187 | 0 | *valid = field->valid; |
188 | 0 | if (field->valid) { |
189 | 0 | memcpy(value, field->data, sizeof(uint32_t)); |
190 | 0 | *value = le32toh(*value); |
191 | 0 | } |
192 | 0 | *buffer += |
193 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint32_t) - 1; |
194 | 0 | *buffer_size -= |
195 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint32_t) - 1; |
196 | 0 | return true; |
197 | 0 | } |
198 | | |
199 | | bool decode_nsm_firmware_aggregate_tag_uint64(uint8_t **buffer, uint8_t *tag, |
200 | | uint8_t *valid, uint64_t *value, |
201 | | uint16_t *buffer_size) |
202 | 0 | { |
203 | 0 | if (*buffer_size < |
204 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint64_t) - 1) { |
205 | 0 | return false; |
206 | 0 | } |
207 | 0 | struct nsm_firmware_aggregate_tag *field = |
208 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
209 | 0 | *tag = field->tag; |
210 | 0 | *valid = field->valid; |
211 | 0 | if (field->valid) { |
212 | 0 | memcpy(value, field->data, sizeof(uint64_t)); |
213 | 0 | *value = le64toh(*value); |
214 | 0 | } |
215 | 0 | *buffer += |
216 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint64_t) - 1; |
217 | 0 | *buffer_size -= |
218 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + sizeof(uint64_t) - 1; |
219 | 0 | return true; |
220 | 0 | } |
221 | | |
222 | | bool decode_nsm_firmware_aggregate_tag_uint8_array(uint8_t **buffer, |
223 | | uint8_t *tag, uint8_t *valid, |
224 | | uint8_t *value, |
225 | | uint16_t *buffer_size) |
226 | 0 | { |
227 | 0 | uint16_t length; |
228 | 0 | if (*buffer_size < sizeof(struct nsm_firmware_aggregate_tag) + 4 - 1) { |
229 | 0 | return false; |
230 | 0 | } |
231 | | |
232 | 0 | struct nsm_firmware_aggregate_tag *field = |
233 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
234 | 0 | *tag = field->tag; |
235 | 0 | *valid = field->valid; |
236 | 0 | length = 1 << field->length; |
237 | 0 | if (*buffer_size < |
238 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + length - 1) { |
239 | 0 | return false; |
240 | 0 | } |
241 | | |
242 | 0 | if (field->valid) { |
243 | 0 | memcpy(value, field->data, length); |
244 | 0 | } |
245 | |
|
246 | 0 | *buffer += sizeof(struct nsm_firmware_aggregate_tag) + length - 1; |
247 | 0 | *buffer_size -= sizeof(struct nsm_firmware_aggregate_tag) + length - 1; |
248 | 0 | return true; |
249 | 0 | } |
250 | | |
251 | | /** |
252 | | * Skip the tag data by advancing the pointer |
253 | | * @param buffer: pointer to the buffer |
254 | | * @param buffer_size: size of the buffer |
255 | | * @return true if the tag is skipped, false otherwise |
256 | | */ |
257 | | bool decode_nsm_firmware_aggregate_tag_skip(uint8_t **buffer, |
258 | | uint16_t *buffer_size) |
259 | 0 | { |
260 | 0 | if (*buffer_size < sizeof(struct nsm_firmware_aggregate_tag)) { |
261 | 0 | return false; |
262 | 0 | } |
263 | | |
264 | 0 | struct nsm_firmware_aggregate_tag *field = |
265 | 0 | (struct nsm_firmware_aggregate_tag *)*buffer; |
266 | |
|
267 | 0 | size_t data_len = 1 << field->length; |
268 | 0 | size_t consumed_len = |
269 | 0 | sizeof(struct nsm_firmware_aggregate_tag) + data_len - 1; |
270 | |
|
271 | 0 | if (*buffer_size < consumed_len) { |
272 | 0 | return false; |
273 | 0 | } |
274 | | |
275 | 0 | *buffer += consumed_len; |
276 | 0 | *buffer_size -= consumed_len; |
277 | 0 | return true; |
278 | 0 | } |
279 | | |
280 | | int decode_nsm_query_get_erot_state_parameters_req( |
281 | | const struct nsm_msg *msg, size_t msg_len, |
282 | | struct nsm_firmware_erot_state_info_req *fw_req) |
283 | 0 | { |
284 | 0 | if (msg == NULL || fw_req == NULL) { |
285 | 0 | return NSM_SW_ERROR_NULL; |
286 | 0 | } |
287 | | |
288 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
289 | 0 | sizeof(struct nsm_firmware_get_erot_state_info_req)) { |
290 | 0 | return NSM_SW_ERROR_LENGTH; |
291 | 0 | } |
292 | | |
293 | 0 | struct nsm_firmware_get_erot_state_info_req *request = |
294 | 0 | (struct nsm_firmware_get_erot_state_info_req *)msg->payload; |
295 | 0 | if (request->hdr.data_size < sizeof(*fw_req)) { |
296 | 0 | return NSM_SW_ERROR_DATA; |
297 | 0 | } |
298 | | |
299 | 0 | *fw_req = request->fq_req; |
300 | |
|
301 | 0 | return NSM_SW_SUCCESS; |
302 | 0 | } |
303 | | |
304 | | int encode_nsm_query_get_erot_state_parameters_req( |
305 | | uint8_t instance_id, const struct nsm_firmware_erot_state_info_req *fw_req, |
306 | | struct nsm_msg *msg) |
307 | 0 | { |
308 | 0 | if (msg == NULL) { |
309 | 0 | return NSM_SW_ERROR_NULL; |
310 | 0 | } |
311 | | |
312 | 0 | struct nsm_header_info header = {0}; |
313 | 0 | header.nsm_msg_type = NSM_REQUEST; |
314 | 0 | header.instance_id = instance_id; |
315 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
316 | |
|
317 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
318 | 0 | if (rc != NSM_SUCCESS) { |
319 | 0 | return rc; |
320 | 0 | } |
321 | | |
322 | 0 | struct nsm_firmware_get_erot_state_info_req *request = |
323 | 0 | (struct nsm_firmware_get_erot_state_info_req *)msg->payload; |
324 | 0 | request->hdr.command = NSM_FW_GET_EROT_STATE_INFORMATION; |
325 | 0 | request->hdr.data_size = |
326 | 0 | htole16(sizeof(struct nsm_firmware_erot_state_info_req)); |
327 | 0 | memcpy(&request->fq_req, fw_req, |
328 | 0 | sizeof(struct nsm_firmware_erot_state_info_req)); |
329 | |
|
330 | 0 | return NSM_SW_SUCCESS; |
331 | 0 | } |
332 | | |
333 | | int encode_nsm_query_get_erot_state_parameters_resp( |
334 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
335 | | struct nsm_firmware_erot_state_info_resp *fw_info, struct nsm_msg *msg) |
336 | 0 | { |
337 | 0 | if (msg == NULL) { |
338 | 0 | return NSM_SW_ERROR_NULL; |
339 | 0 | } |
340 | | |
341 | 0 | struct nsm_header_info header = {0}; |
342 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
343 | 0 | header.instance_id = instance_id; |
344 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
345 | |
|
346 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
347 | 0 | if (rc != NSM_SW_SUCCESS) { |
348 | 0 | return rc; |
349 | 0 | } |
350 | | |
351 | 0 | if (cc != NSM_SUCCESS) { |
352 | 0 | return encode_reason_code( |
353 | 0 | cc, reason_code, NSM_FW_GET_EROT_STATE_INFORMATION, msg); |
354 | 0 | } |
355 | | |
356 | 0 | struct nsm_firmware_get_erot_state_info_resp *response = |
357 | 0 | (struct nsm_firmware_get_erot_state_info_resp *)msg->payload; |
358 | 0 | response->hdr.command = NSM_FW_GET_EROT_STATE_INFORMATION; |
359 | 0 | response->hdr.completion_code = cc; |
360 | |
|
361 | 0 | uint16_t telemetry_count = 0; |
362 | 0 | uint16_t msg_size = sizeof(struct nsm_common_telemetry_resp); |
363 | |
|
364 | 0 | uint8_t *ptr = &(response->payload[0]); |
365 | |
|
366 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
367 | 0 | &ptr, NSM_FIRMWARE_BACKGROUND_COPY_POLICY, |
368 | 0 | fw_info->fq_resp_hdr.background_copy_policy, &msg_size); |
369 | 0 | telemetry_count++; |
370 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
371 | 0 | &ptr, NSM_FIRMWARE_ACTIVE_FIRMWARE_SLOT, |
372 | 0 | fw_info->fq_resp_hdr.active_slot, &msg_size); |
373 | 0 | telemetry_count++; |
374 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
375 | 0 | &ptr, NSM_FIRMWARE_ACTIVE_KEY_SET, |
376 | 0 | fw_info->fq_resp_hdr.active_keyset, &msg_size); |
377 | 0 | telemetry_count++; |
378 | 0 | encode_nsm_firmware_aggregate_tag_uint16( |
379 | 0 | &ptr, NSM_FIRMWARE_MINIMUM_SECURITY_VERSION_NUMBER, |
380 | 0 | fw_info->fq_resp_hdr.minimum_security_version, &msg_size); |
381 | 0 | telemetry_count++; |
382 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
383 | 0 | &ptr, NSM_FIRMWARE_INBAND_UPDATE_POLICY, |
384 | 0 | fw_info->fq_resp_hdr.inband_update_policy, &msg_size); |
385 | 0 | telemetry_count++; |
386 | 0 | encode_nsm_firmware_aggregate_tag_uint64( |
387 | 0 | &ptr, NSM_FIRMWARE_BOOT_STATUS_CODE, |
388 | 0 | fw_info->fq_resp_hdr.boot_status_code, &msg_size); |
389 | 0 | telemetry_count++; |
390 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
391 | 0 | &ptr, NSM_FIRMWARE_FIRMWARE_SLOT_COUNT, |
392 | 0 | fw_info->fq_resp_hdr.firmware_slot_count, &msg_size); |
393 | 0 | telemetry_count++; |
394 | |
|
395 | 0 | for (int i = 0; i < fw_info->fq_resp_hdr.firmware_slot_count; i++) { |
396 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
397 | 0 | &ptr, NSM_FIRMWARE_FIRMWARE_SLOT_ID, |
398 | 0 | fw_info->slot_info[i].slot_id, &msg_size); |
399 | 0 | telemetry_count++; |
400 | 0 | encode_nsm_firmware_aggregate_tag_uint8_array( |
401 | 0 | &ptr, NSM_FIRMWARE_FIRMWARE_VERSION_STRING, |
402 | 0 | (uint8_t *)(&( |
403 | 0 | fw_info->slot_info[i].firmware_version_string[0])), |
404 | 0 | &msg_size); |
405 | 0 | telemetry_count++; |
406 | 0 | encode_nsm_firmware_aggregate_tag_uint32( |
407 | 0 | &ptr, NSM_FIRMWARE_VERSION_COMPARISON_STAMP, |
408 | 0 | fw_info->slot_info[i].version_comparison_stamp, &msg_size); |
409 | 0 | telemetry_count++; |
410 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
411 | 0 | &ptr, NSM_FIRMWARE_BUILD_TYPE, |
412 | 0 | fw_info->slot_info[i].build_type, &msg_size); |
413 | 0 | telemetry_count++; |
414 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
415 | 0 | &ptr, NSM_FIRMWARE_SIGNING_TYPE, |
416 | 0 | fw_info->slot_info[i].signing_type, &msg_size); |
417 | 0 | telemetry_count++; |
418 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
419 | 0 | &ptr, NSM_FIRMWARE_WRITE_PROTECT_STATE, |
420 | 0 | fw_info->slot_info[i].write_protect_state, &msg_size); |
421 | 0 | telemetry_count++; |
422 | 0 | encode_nsm_firmware_aggregate_tag_uint8( |
423 | 0 | &ptr, NSM_FIRMWARE_FIRMWARE_STATE, |
424 | 0 | fw_info->slot_info[i].firmware_state, &msg_size); |
425 | 0 | telemetry_count++; |
426 | 0 | encode_nsm_firmware_aggregate_tag_uint16( |
427 | 0 | &ptr, NSM_FIRMWARE_SECURITY_VERSION_NUMBER, |
428 | 0 | fw_info->slot_info[i].security_version_number, &msg_size); |
429 | 0 | telemetry_count++; |
430 | 0 | encode_nsm_firmware_aggregate_tag_uint16( |
431 | 0 | &ptr, NSM_FIRMWARE_SIGNING_KEY_INDEX, |
432 | 0 | fw_info->slot_info[i].signing_key_index, &msg_size); |
433 | 0 | telemetry_count++; |
434 | 0 | } |
435 | |
|
436 | 0 | response->hdr.telemetry_count = htole16(telemetry_count); |
437 | |
|
438 | 0 | DBG1(printf("Telemetry count = %u, resp buffer (size = %u):\n", |
439 | 0 | (uint32_t)telemetry_count, (uint32_t)msg_size);) |
440 | 0 | DBG1(printArrayAsHex(&(response->payload[0]), msg_size);) |
441 | |
|
442 | 0 | return NSM_SW_SUCCESS; |
443 | 0 | } |
444 | | |
445 | | int decode_nsm_query_firmware_header_information( |
446 | | struct nsm_firmware_erot_state_info_hdr_resp *fw_info_hdr, uint8_t **ptr, |
447 | | uint16_t *payload_size, uint16_t *telemetry_count) |
448 | 0 | { |
449 | 0 | uint8_t tag, valid; |
450 | 0 | bool rc_ok; |
451 | |
|
452 | 0 | while ((*payload_size >= sizeof(struct nsm_firmware_aggregate_tag)) && |
453 | 0 | (*telemetry_count > 0)) { |
454 | 0 | struct nsm_firmware_aggregate_tag *field = |
455 | 0 | (struct nsm_firmware_aggregate_tag *)*ptr; |
456 | 0 | tag = field->tag; |
457 | |
|
458 | 0 | if (tag == NSM_FIRMWARE_BACKGROUND_COPY_POLICY) { |
459 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
460 | 0 | ptr, &tag, &valid, |
461 | 0 | &(fw_info_hdr->background_copy_policy), |
462 | 0 | payload_size); |
463 | 0 | if (rc_ok) { |
464 | 0 | (*telemetry_count)--; |
465 | 0 | DBG2(printf( |
466 | 0 | "Decoded " |
467 | 0 | "NSM_FIRMWARE_BACKGROUND_COPY_POLICY, " |
468 | 0 | "value = 0x%02x\n", |
469 | 0 | fw_info_hdr->background_copy_policy);) |
470 | 0 | } |
471 | 0 | } else if (tag == NSM_FIRMWARE_ACTIVE_FIRMWARE_SLOT) { |
472 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
473 | 0 | ptr, &tag, &valid, &(fw_info_hdr->active_slot), |
474 | 0 | payload_size); |
475 | 0 | if (rc_ok) { |
476 | 0 | (*telemetry_count)--; |
477 | 0 | DBG2(printf("Decoded " |
478 | 0 | "NSM_FIRMWARE_ACTIVE_FIRMWARE_SLOT," |
479 | 0 | " value = 0x%02x\n", |
480 | 0 | fw_info_hdr->active_slot);) |
481 | 0 | } |
482 | 0 | } else if (tag == NSM_FIRMWARE_ACTIVE_KEY_SET) { |
483 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
484 | 0 | ptr, &tag, &valid, &(fw_info_hdr->active_keyset), |
485 | 0 | payload_size); |
486 | 0 | if (rc_ok) { |
487 | 0 | (*telemetry_count)--; |
488 | 0 | DBG2(printf( |
489 | 0 | "Decoded NSM_FIRMWARE_ACTIVE_KEY_SET, " |
490 | 0 | "value = 0x%02x\n", |
491 | 0 | fw_info_hdr->active_keyset);) |
492 | 0 | } |
493 | 0 | } else if (tag == |
494 | 0 | NSM_FIRMWARE_MINIMUM_SECURITY_VERSION_NUMBER) { |
495 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint16( |
496 | 0 | ptr, &tag, &valid, |
497 | 0 | &(fw_info_hdr->minimum_security_version), |
498 | 0 | payload_size); |
499 | 0 | if (rc_ok) { |
500 | 0 | (*telemetry_count)--; |
501 | 0 | DBG2( |
502 | 0 | printf( |
503 | 0 | "Decoded " |
504 | 0 | "NSM_FIRMWARE_MINIMUM_SECURITY_VERSION_" |
505 | 0 | "NUMBER, value = 0x%04x\n", |
506 | 0 | fw_info_hdr->minimum_security_version);) |
507 | 0 | } |
508 | 0 | } else if (tag == NSM_FIRMWARE_INBAND_UPDATE_POLICY) { |
509 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
510 | 0 | ptr, &tag, &valid, |
511 | 0 | &(fw_info_hdr->inband_update_policy), payload_size); |
512 | 0 | if (rc_ok) { |
513 | 0 | (*telemetry_count)--; |
514 | 0 | DBG2(printf("Decoded " |
515 | 0 | "NSM_FIRMWARE_INBAND_UPDATE_POLICY," |
516 | 0 | " value = 0x%02x\n", |
517 | 0 | fw_info_hdr->inband_update_policy);) |
518 | 0 | } |
519 | 0 | } else if (tag == NSM_FIRMWARE_BOOT_STATUS_CODE) { |
520 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint64( |
521 | 0 | ptr, &tag, &valid, &(fw_info_hdr->boot_status_code), |
522 | 0 | payload_size); |
523 | 0 | if (rc_ok) { |
524 | 0 | (*telemetry_count)--; |
525 | 0 | DBG2(printf("Decoded " |
526 | 0 | "NSM_FIRMWARE_BOOT_STATUS_CODE," |
527 | 0 | " value = 0x%016lx\n", |
528 | 0 | fw_info_hdr->boot_status_code);) |
529 | 0 | } |
530 | 0 | } else if (tag == NSM_FIRMWARE_FIRMWARE_SLOT_COUNT) { |
531 | 0 | if (decode_nsm_firmware_aggregate_tag_uint8( |
532 | 0 | ptr, &tag, &valid, |
533 | 0 | &(fw_info_hdr->firmware_slot_count), |
534 | 0 | payload_size)) { |
535 | 0 | (*telemetry_count)--; |
536 | 0 | DBG2(printf("Decoded " |
537 | 0 | "NSM_FIRMWARE_FIRMWARE_SLOT_COUNT, " |
538 | 0 | "value = 0x%02x\n", |
539 | 0 | fw_info_hdr->firmware_slot_count);) |
540 | 0 | break; |
541 | 0 | } |
542 | 0 | rc_ok = false; |
543 | 0 | } else { |
544 | | /* Skip unsupported tag */ |
545 | 0 | DBG2(printf( |
546 | 0 | "Skipping unsupported tag in header: 0x%02x\n", |
547 | 0 | field->tag);) |
548 | 0 | DBG2(printf("Left telemetries: %u, left payload: %u\n", |
549 | 0 | (uint32_t)(*telemetry_count), |
550 | 0 | (uint32_t)(*payload_size));) |
551 | 0 | (*telemetry_count)--; |
552 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_skip( |
553 | 0 | ptr, payload_size); |
554 | 0 | if (!rc_ok) { |
555 | 0 | DBGE(printf("Error: The decoded message header " |
556 | 0 | "is not " |
557 | 0 | "properly encoded\n");) |
558 | 0 | DBGE(printf("Left telemetries: %u, left " |
559 | 0 | "payload: %u\n", |
560 | 0 | (uint32_t)(*telemetry_count), |
561 | 0 | (uint32_t)(*payload_size));) |
562 | 0 | return NSM_SW_ERROR_LENGTH; |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | 0 | if (!rc_ok) { |
567 | 0 | DBGE(printf("Error: The decoded message header is not " |
568 | 0 | "properly encoded\n");) |
569 | 0 | DBGE(printf("Left telemetries: %u, left payload: %u\n", |
570 | 0 | (uint32_t)(*telemetry_count), |
571 | 0 | (uint32_t)(*payload_size));) |
572 | 0 | return NSM_SW_ERROR_LENGTH; |
573 | 0 | } |
574 | 0 | } |
575 | | |
576 | 0 | DBG2(printf("Success in decoding the response header\n");) |
577 | 0 | return NSM_SW_SUCCESS; |
578 | 0 | } |
579 | | |
580 | | int decode_nsm_query_firmware_slot_information( |
581 | | struct nsm_firmware_slot_info *fw_slot_info, uint8_t **ptr, |
582 | | uint16_t *payload_size, uint16_t *telemetry_count) |
583 | 0 | { |
584 | 0 | uint8_t tag, valid; |
585 | 0 | bool rc_ok; |
586 | |
|
587 | 0 | if ((*payload_size < sizeof(struct nsm_firmware_aggregate_tag)) || |
588 | 0 | (*telemetry_count == 0)) { |
589 | 0 | DBG2(printf("Error: Expected NSM_FIRMWARE_FIRMWARE_SLOT_ID, " |
590 | 0 | "but there is no more tags in the message\n");) |
591 | 0 | return NSM_SW_ERROR_DATA; |
592 | 0 | } |
593 | | |
594 | 0 | struct nsm_firmware_aggregate_tag *field = |
595 | 0 | (struct nsm_firmware_aggregate_tag *)*ptr; |
596 | 0 | tag = field->tag; |
597 | | |
598 | | // Firmware slot ID tag must be always as the first one |
599 | 0 | if (tag == NSM_FIRMWARE_FIRMWARE_SLOT_ID) { |
600 | 0 | if (!decode_nsm_firmware_aggregate_tag_uint8( |
601 | 0 | ptr, &tag, &valid, &(fw_slot_info->slot_id), |
602 | 0 | payload_size)) { |
603 | 0 | return NSM_SW_ERROR_LENGTH; |
604 | 0 | } |
605 | 0 | (*telemetry_count)--; |
606 | 0 | DBG2(printf( |
607 | 0 | "Decoded NSM_FIRMWARE_FIRMWARE_SLOT_ID, value = %u\n", |
608 | 0 | fw_slot_info->slot_id);) |
609 | 0 | } else { |
610 | 0 | return NSM_SW_ERROR_DATA; |
611 | 0 | } |
612 | | |
613 | 0 | while ((*payload_size >= sizeof(struct nsm_firmware_aggregate_tag)) && |
614 | 0 | (*telemetry_count > 0)) { |
615 | 0 | field = (struct nsm_firmware_aggregate_tag *)*ptr; |
616 | 0 | tag = field->tag; |
617 | |
|
618 | 0 | if (tag == NSM_FIRMWARE_FIRMWARE_VERSION_STRING) { |
619 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8_array( |
620 | 0 | ptr, &tag, &valid, |
621 | 0 | (uint8_t *)(&( |
622 | 0 | fw_slot_info->firmware_version_string[0])), |
623 | 0 | payload_size); |
624 | 0 | if (rc_ok) { |
625 | 0 | (*telemetry_count)--; |
626 | 0 | DBG2( |
627 | 0 | printf( |
628 | 0 | "Decoded " |
629 | 0 | "NSM_FIRMWARE_FIRMWARE_VERSION_STRING, " |
630 | 0 | "value = %s\n", |
631 | 0 | (char |
632 | 0 | *)(fw_slot_info |
633 | 0 | ->firmware_version_string));) |
634 | 0 | } |
635 | 0 | } else if (tag == NSM_FIRMWARE_VERSION_COMPARISON_STAMP) { |
636 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint32( |
637 | 0 | ptr, &tag, &valid, |
638 | 0 | &(fw_slot_info->version_comparison_stamp), |
639 | 0 | payload_size); |
640 | 0 | if (rc_ok) { |
641 | 0 | (*telemetry_count)--; |
642 | 0 | DBG2(printf("Decoded " |
643 | 0 | "NSM_FIRMWARE_VERSION_COMPARISON_" |
644 | 0 | "STAMP, value = %u\n", |
645 | 0 | fw_slot_info |
646 | 0 | ->version_comparison_stamp);) |
647 | 0 | } |
648 | 0 | } else if (tag == NSM_FIRMWARE_BUILD_TYPE) { |
649 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
650 | 0 | ptr, &tag, &valid, &(fw_slot_info->build_type), |
651 | 0 | payload_size); |
652 | 0 | if (rc_ok) { |
653 | 0 | (*telemetry_count)--; |
654 | 0 | DBG2(printf("Decoded NSM_FIRMWARE_BUILD_TYPE, " |
655 | 0 | "value = %u\n", |
656 | 0 | fw_slot_info->build_type);) |
657 | 0 | } |
658 | 0 | } else if (tag == NSM_FIRMWARE_SIGNING_TYPE) { |
659 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
660 | 0 | ptr, &tag, &valid, &(fw_slot_info->signing_type), |
661 | 0 | payload_size); |
662 | 0 | if (rc_ok) { |
663 | 0 | (*telemetry_count)--; |
664 | 0 | DBG2( |
665 | 0 | printf("Decoded NSM_FIRMWARE_SIGNING_TYPE, " |
666 | 0 | "value = %u\n", |
667 | 0 | fw_slot_info->signing_type);) |
668 | 0 | } |
669 | 0 | } else if (tag == NSM_FIRMWARE_WRITE_PROTECT_STATE) { |
670 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
671 | 0 | ptr, &tag, &valid, |
672 | 0 | &(fw_slot_info->write_protect_state), payload_size); |
673 | 0 | if (rc_ok) { |
674 | 0 | (*telemetry_count)--; |
675 | 0 | DBG2(printf("Decoded " |
676 | 0 | "NSM_FIRMWARE_WRITE_PROTECT_STATE, " |
677 | 0 | "value = %u\n", |
678 | 0 | fw_slot_info->write_protect_state);) |
679 | 0 | } |
680 | 0 | } else if (tag == NSM_FIRMWARE_FIRMWARE_STATE) { |
681 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint8( |
682 | 0 | ptr, &tag, &valid, &(fw_slot_info->firmware_state), |
683 | 0 | payload_size); |
684 | 0 | if (rc_ok) { |
685 | 0 | (*telemetry_count)--; |
686 | 0 | DBG2(printf( |
687 | 0 | "Decoded NSM_FIRMWARE_FIRMWARE_STATE, " |
688 | 0 | "value = %u\n", |
689 | 0 | fw_slot_info->firmware_state);) |
690 | 0 | } |
691 | 0 | } else if (tag == NSM_FIRMWARE_SECURITY_VERSION_NUMBER) { |
692 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint16( |
693 | 0 | ptr, &tag, &valid, |
694 | 0 | &(fw_slot_info->security_version_number), |
695 | 0 | payload_size); |
696 | 0 | if (rc_ok) { |
697 | 0 | (*telemetry_count)--; |
698 | 0 | DBG2( |
699 | 0 | printf( |
700 | 0 | "Decoded " |
701 | 0 | "NSM_FIRMWARE_SECURITY_VERSION_NUMBER, " |
702 | 0 | "value = %u\n", |
703 | 0 | fw_slot_info->security_version_number);) |
704 | 0 | } |
705 | 0 | } else if (tag == NSM_FIRMWARE_SIGNING_KEY_INDEX) { |
706 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_uint16( |
707 | 0 | ptr, &tag, &valid, |
708 | 0 | &(fw_slot_info->signing_key_index), payload_size); |
709 | 0 | if (rc_ok) { |
710 | 0 | (*telemetry_count)--; |
711 | 0 | DBG2(printf("Decoded " |
712 | 0 | "NSM_FIRMWARE_SIGNING_KEY_INDEX, " |
713 | 0 | "value = %u\n", |
714 | 0 | fw_slot_info->signing_key_index);) |
715 | 0 | } |
716 | 0 | } else if (tag == NSM_FIRMWARE_FIRMWARE_SLOT_ID) { |
717 | | /* we are good, we reached new firmware slot id */ |
718 | 0 | return NSM_SW_SUCCESS; |
719 | 0 | } else { |
720 | | /* Skip unsupported tag */ |
721 | 0 | DBG2(printf("Skipping unsupported tag in slot " |
722 | 0 | "information: 0x%02x\n", |
723 | 0 | field->tag);) |
724 | 0 | DBG2(printf("Left telemetries: %u, left payload: %u\n", |
725 | 0 | (uint32_t)(*telemetry_count), |
726 | 0 | (uint32_t)(*payload_size));) |
727 | 0 | (*telemetry_count)--; |
728 | 0 | rc_ok = decode_nsm_firmware_aggregate_tag_skip( |
729 | 0 | ptr, payload_size); |
730 | 0 | if (!rc_ok) { |
731 | 0 | DBGE(printf("Error: The decoded message slot " |
732 | 0 | "information is not properly " |
733 | 0 | "encoded\n");) |
734 | 0 | DBGE(printf("Left telemetries: %u, left " |
735 | 0 | "payload: %u\n", |
736 | 0 | (uint32_t)(*telemetry_count), |
737 | 0 | (uint32_t)(*payload_size));) |
738 | 0 | return NSM_SW_ERROR_LENGTH; |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | 0 | if (!rc_ok) { |
743 | 0 | DBGE(printf("Error: The decoded message slot " |
744 | 0 | "information is not properly encoded\n");) |
745 | 0 | DBGE(printf("Left telemetries: %u, left payload: %u\n", |
746 | 0 | (uint32_t)(*telemetry_count), |
747 | 0 | (uint32_t)(*payload_size));) |
748 | 0 | return NSM_SW_ERROR_LENGTH; |
749 | 0 | } |
750 | 0 | } |
751 | | |
752 | 0 | DBG2(printf("Success in decoding the response slot information\n");) |
753 | 0 | return NSM_SW_SUCCESS; |
754 | 0 | } |
755 | | |
756 | | int decode_nsm_query_get_erot_state_parameters_resp( |
757 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
758 | | uint16_t *reason_code, struct nsm_firmware_erot_state_info_resp *fw_resp) |
759 | 0 | { |
760 | 0 | if (msg == NULL || fw_resp == NULL) { |
761 | 0 | return NSM_SW_ERROR_NULL; |
762 | 0 | } |
763 | | |
764 | 0 | DBG1(printf("Received Resp buffer (size = %zi):\n", msg_len);) |
765 | 0 | DBG1(printArrayAsHex(&(msg->payload[0]), msg_len);) |
766 | | |
767 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
768 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
769 | 0 | return rc; |
770 | 0 | } |
771 | | |
772 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
773 | 0 | sizeof(struct nsm_firmware_aggregate_tag)) { |
774 | 0 | return NSM_SW_ERROR_LENGTH; |
775 | 0 | } |
776 | | |
777 | 0 | struct nsm_firmware_get_erot_state_info_resp *resp = |
778 | 0 | (struct nsm_firmware_get_erot_state_info_resp *)msg->payload; |
779 | |
|
780 | 0 | uint8_t *ptr = &(resp->payload[0]); |
781 | 0 | uint16_t telemetry_count = resp->hdr.telemetry_count; |
782 | 0 | uint16_t payload_size = (uint16_t)msg_len - sizeof(struct nsm_msg_hdr) - |
783 | 0 | sizeof(struct nsm_common_telemetry_resp); |
784 | 0 | DBG2(printf("Telemetry count = %u, msg max size = %u:\n", |
785 | 0 | (uint32_t)telemetry_count, (uint32_t)payload_size);) |
786 | |
|
787 | 0 | int ret = decode_nsm_query_firmware_header_information( |
788 | 0 | &(fw_resp->fq_resp_hdr), &ptr, &payload_size, &telemetry_count); |
789 | 0 | if (ret) { |
790 | 0 | DBGE(printf("Full payload (len = %zi):\n", msg_len);) |
791 | 0 | DBGE(printArrayAsHex((const uint8_t *)msg, msg_len);) |
792 | 0 | return ret; |
793 | 0 | } |
794 | | |
795 | 0 | DBG2(printf("Payload remaining size = %u):\n", (uint32_t)payload_size);) |
796 | 0 | if (fw_resp->fq_resp_hdr.firmware_slot_count > 0) { |
797 | 0 | int slot_info_len = sizeof(struct nsm_firmware_slot_info) * |
798 | 0 | fw_resp->fq_resp_hdr.firmware_slot_count; |
799 | 0 | fw_resp->slot_info = malloc(slot_info_len); |
800 | 0 | memset((char *)(fw_resp->slot_info), 0, slot_info_len); |
801 | |
|
802 | 0 | for (int i = 0; i < fw_resp->fq_resp_hdr.firmware_slot_count; |
803 | 0 | i++) { |
804 | 0 | int ret = decode_nsm_query_firmware_slot_information( |
805 | 0 | &(fw_resp->slot_info[i]), &ptr, &payload_size, |
806 | 0 | &telemetry_count); |
807 | 0 | if (ret) { |
808 | 0 | DBGE(printf("Full payload (len = %zi):\n", |
809 | 0 | msg_len);) |
810 | 0 | DBGE(printArrayAsHex((const uint8_t *)msg, |
811 | 0 | msg_len);) |
812 | 0 | return ret; |
813 | 0 | } |
814 | 0 | } |
815 | 0 | } else { |
816 | 0 | fw_resp->slot_info = NULL; |
817 | 0 | } |
818 | | |
819 | 0 | return NSM_SW_SUCCESS; |
820 | 0 | } |
821 | | |
822 | | int encode_nsm_firmware_irreversible_config_req( |
823 | | uint8_t instance_id, |
824 | | const struct nsm_firmware_irreversible_config_req *fw_req, |
825 | | struct nsm_msg *msg) |
826 | 0 | { |
827 | 0 | if (msg == NULL) { |
828 | 0 | return NSM_SW_ERROR_NULL; |
829 | 0 | } |
830 | 0 | struct nsm_header_info header = {0}; |
831 | 0 | header.nsm_msg_type = NSM_REQUEST; |
832 | 0 | header.instance_id = instance_id; |
833 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
834 | |
|
835 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
836 | 0 | if (rc != NSM_SUCCESS) { |
837 | 0 | return rc; |
838 | 0 | } |
839 | | |
840 | 0 | struct nsm_firmware_irreversible_config_req_command *request = |
841 | 0 | (struct nsm_firmware_irreversible_config_req_command *)msg->payload; |
842 | 0 | request->hdr.command = NSM_FW_IRREVERSABLE_CONFIGURATION; |
843 | 0 | request->hdr.data_size = |
844 | 0 | sizeof(struct nsm_firmware_irreversible_config_req); |
845 | 0 | memcpy(&request->irreversible_cfg_req, fw_req, |
846 | 0 | sizeof(struct nsm_firmware_irreversible_config_req)); |
847 | |
|
848 | 0 | return NSM_SW_SUCCESS; |
849 | 0 | } |
850 | | |
851 | | int decode_nsm_firmware_irreversible_config_req( |
852 | | const struct nsm_msg *msg, size_t msg_len, |
853 | | struct nsm_firmware_irreversible_config_req *fw_req) |
854 | 0 | { |
855 | 0 | if (msg == NULL || fw_req == NULL) { |
856 | 0 | return NSM_SW_ERROR_NULL; |
857 | 0 | } |
858 | | |
859 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
860 | 0 | sizeof(struct nsm_firmware_irreversible_config_req)) { |
861 | 0 | return NSM_SW_ERROR_LENGTH; |
862 | 0 | } |
863 | | |
864 | 0 | struct nsm_firmware_irreversible_config_req_command *request = |
865 | 0 | (struct nsm_firmware_irreversible_config_req_command *)msg->payload; |
866 | 0 | if (request->hdr.data_size < sizeof(*fw_req)) { |
867 | 0 | return NSM_SW_ERROR_DATA; |
868 | 0 | } |
869 | | |
870 | 0 | *fw_req = request->irreversible_cfg_req; |
871 | |
|
872 | 0 | return NSM_SW_SUCCESS; |
873 | 0 | } |
874 | | |
875 | | int encode_nsm_firmware_irreversible_config_request_0_resp( |
876 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
877 | | struct nsm_firmware_irreversible_config_request_0_resp *cfg_resp, |
878 | | struct nsm_msg *msg) |
879 | 0 | { |
880 | 0 | if (msg == NULL) { |
881 | 0 | return NSM_SW_ERROR_NULL; |
882 | 0 | } |
883 | | |
884 | 0 | struct nsm_header_info header = {0}; |
885 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
886 | 0 | header.instance_id = instance_id; |
887 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
888 | |
|
889 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
890 | 0 | if (rc != NSM_SW_SUCCESS) { |
891 | 0 | return rc; |
892 | 0 | } |
893 | | |
894 | 0 | if (cc != NSM_SUCCESS) { |
895 | 0 | return encode_reason_code( |
896 | 0 | cc, reason_code, NSM_FW_IRREVERSABLE_CONFIGURATION, msg); |
897 | 0 | } |
898 | | |
899 | 0 | struct nsm_firmware_irreversible_config_request_0_resp_command |
900 | 0 | *response = |
901 | 0 | (struct nsm_firmware_irreversible_config_request_0_resp_command |
902 | 0 | *)msg->payload; |
903 | 0 | response->hdr.command = NSM_FW_IRREVERSABLE_CONFIGURATION; |
904 | 0 | response->hdr.completion_code = cc; |
905 | |
|
906 | 0 | uint16_t msg_size = |
907 | 0 | sizeof(struct nsm_common_resp) + |
908 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_0_resp); |
909 | |
|
910 | 0 | response->hdr.data_size = htole16(msg_size); |
911 | |
|
912 | 0 | memcpy(&(response->irreversible_cfg_query), cfg_resp, |
913 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_0_resp)); |
914 | |
|
915 | 0 | return NSM_SW_SUCCESS; |
916 | 0 | } |
917 | | |
918 | | int encode_nsm_firmware_irreversible_config_request_1_resp(uint8_t instance_id, |
919 | | uint8_t cc, |
920 | | uint16_t reason_code, |
921 | | struct nsm_msg *msg) |
922 | 0 | { |
923 | 0 | if (msg == NULL) { |
924 | 0 | return NSM_SW_ERROR_NULL; |
925 | 0 | } |
926 | | |
927 | 0 | struct nsm_header_info header = {0}; |
928 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
929 | 0 | header.instance_id = instance_id; |
930 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
931 | |
|
932 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
933 | 0 | if (rc != NSM_SW_SUCCESS) { |
934 | 0 | return rc; |
935 | 0 | } |
936 | | |
937 | 0 | if (cc != NSM_SUCCESS) { |
938 | 0 | return encode_reason_code( |
939 | 0 | cc, reason_code, NSM_FW_IRREVERSABLE_CONFIGURATION, msg); |
940 | 0 | } |
941 | | |
942 | 0 | struct nsm_firmware_irreversible_config_request_1_resp_command |
943 | 0 | *response = |
944 | 0 | (struct nsm_firmware_irreversible_config_request_1_resp_command |
945 | 0 | *)msg->payload; |
946 | 0 | response->hdr.command = NSM_FW_IRREVERSABLE_CONFIGURATION; |
947 | 0 | response->hdr.completion_code = cc; |
948 | |
|
949 | 0 | uint16_t msg_size = sizeof(struct nsm_common_resp); |
950 | |
|
951 | 0 | response->hdr.data_size = htole16(msg_size); |
952 | |
|
953 | 0 | return NSM_SW_SUCCESS; |
954 | 0 | } |
955 | | |
956 | | int encode_nsm_firmware_irreversible_config_request_2_resp( |
957 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
958 | | struct nsm_firmware_irreversible_config_request_2_resp *cfg_resp, |
959 | | struct nsm_msg *msg) |
960 | 0 | { |
961 | 0 | if (msg == NULL) { |
962 | 0 | return NSM_SW_ERROR_NULL; |
963 | 0 | } |
964 | | |
965 | 0 | struct nsm_header_info header = {0}; |
966 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
967 | 0 | header.instance_id = instance_id; |
968 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
969 | |
|
970 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
971 | 0 | if (rc != NSM_SW_SUCCESS) { |
972 | 0 | return rc; |
973 | 0 | } |
974 | | |
975 | 0 | if (cc != NSM_SUCCESS) { |
976 | 0 | return encode_reason_code( |
977 | 0 | cc, reason_code, NSM_FW_IRREVERSABLE_CONFIGURATION, msg); |
978 | 0 | } |
979 | | |
980 | 0 | struct nsm_firmware_irreversible_config_request_2_resp_command |
981 | 0 | *response = |
982 | 0 | (struct nsm_firmware_irreversible_config_request_2_resp_command |
983 | 0 | *)msg->payload; |
984 | 0 | response->hdr.command = NSM_FW_IRREVERSABLE_CONFIGURATION; |
985 | 0 | response->hdr.completion_code = cc; |
986 | |
|
987 | 0 | uint16_t msg_size = |
988 | 0 | sizeof(struct nsm_common_resp) + |
989 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_2_resp); |
990 | |
|
991 | 0 | response->hdr.data_size = htole16(msg_size); |
992 | |
|
993 | 0 | memcpy(&(response->irreversible_cfg_enable_response), cfg_resp, |
994 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_2_resp)); |
995 | |
|
996 | 0 | return NSM_SW_SUCCESS; |
997 | 0 | } |
998 | | |
999 | | int decode_nsm_firmware_irreversible_config_request_0_resp( |
1000 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1001 | | uint16_t *reason_code, |
1002 | | struct nsm_firmware_irreversible_config_request_0_resp *cfg_resp) |
1003 | 0 | { |
1004 | 0 | if (msg == NULL || cfg_resp == NULL) { |
1005 | 0 | return NSM_SW_ERROR_NULL; |
1006 | 0 | } |
1007 | | |
1008 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1009 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1010 | 0 | return rc; |
1011 | 0 | } |
1012 | | |
1013 | 0 | if (msg_len < |
1014 | 0 | sizeof(struct nsm_msg_hdr) + |
1015 | 0 | sizeof( |
1016 | 0 | struct nsm_firmware_irreversible_config_request_0_resp)) { |
1017 | 0 | return NSM_SW_ERROR_LENGTH; |
1018 | 0 | } |
1019 | | |
1020 | 0 | struct nsm_firmware_irreversible_config_request_0_resp_command *resp = |
1021 | 0 | (struct nsm_firmware_irreversible_config_request_0_resp_command *) |
1022 | 0 | msg->payload; |
1023 | |
|
1024 | 0 | memcpy(cfg_resp, &(resp->irreversible_cfg_query), |
1025 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_0_resp)); |
1026 | |
|
1027 | 0 | return NSM_SW_SUCCESS; |
1028 | 0 | } |
1029 | | |
1030 | | int decode_nsm_firmware_irreversible_config_request_1_resp( |
1031 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1032 | | uint16_t *reason_code) |
1033 | 0 | { |
1034 | 0 | if (msg == NULL) { |
1035 | 0 | return NSM_SW_ERROR_NULL; |
1036 | 0 | } |
1037 | | |
1038 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1039 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1040 | 0 | return rc; |
1041 | 0 | } |
1042 | | |
1043 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr)) { |
1044 | 0 | return NSM_SW_ERROR_LENGTH; |
1045 | 0 | } |
1046 | | |
1047 | 0 | return NSM_SW_SUCCESS; |
1048 | 0 | } |
1049 | | |
1050 | | int decode_nsm_firmware_irreversible_config_request_2_resp( |
1051 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1052 | | uint16_t *reason_code, |
1053 | | struct nsm_firmware_irreversible_config_request_2_resp *cfg_resp) |
1054 | 0 | { |
1055 | 0 | if (msg == NULL || cfg_resp == NULL) { |
1056 | 0 | return NSM_SW_ERROR_NULL; |
1057 | 0 | } |
1058 | | |
1059 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1060 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1061 | 0 | return rc; |
1062 | 0 | } |
1063 | | |
1064 | 0 | if (msg_len < |
1065 | 0 | sizeof(struct nsm_msg_hdr) + |
1066 | 0 | sizeof( |
1067 | 0 | struct nsm_firmware_irreversible_config_request_2_resp)) { |
1068 | 0 | return NSM_SW_ERROR_LENGTH; |
1069 | 0 | } |
1070 | | |
1071 | 0 | struct nsm_firmware_irreversible_config_request_2_resp_command *resp = |
1072 | 0 | (struct nsm_firmware_irreversible_config_request_2_resp_command *) |
1073 | 0 | msg->payload; |
1074 | |
|
1075 | 0 | memcpy(cfg_resp, &(resp->irreversible_cfg_enable_response), |
1076 | 0 | sizeof(struct nsm_firmware_irreversible_config_request_2_resp)); |
1077 | |
|
1078 | 0 | return NSM_SW_SUCCESS; |
1079 | 0 | } |
1080 | | |
1081 | | int decode_nsm_code_auth_key_perm_query_req( |
1082 | | const struct nsm_msg *msg, size_t msg_len, |
1083 | | uint16_t *component_classification, uint16_t *component_identifier, |
1084 | | uint8_t *component_classification_index) |
1085 | 0 | { |
1086 | 0 | if (msg == NULL || component_classification == NULL || |
1087 | 0 | component_identifier == NULL || |
1088 | 0 | component_classification_index == NULL) { |
1089 | 0 | return NSM_SW_ERROR_NULL; |
1090 | 0 | } |
1091 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
1092 | 0 | sizeof(struct nsm_code_auth_key_perm_query_req)) { |
1093 | 0 | return NSM_SW_ERROR_LENGTH; |
1094 | 0 | } |
1095 | | |
1096 | 0 | struct nsm_code_auth_key_perm_query_req *req = |
1097 | 0 | (struct nsm_code_auth_key_perm_query_req *)msg->payload; |
1098 | 0 | if (req->hdr.data_size < |
1099 | 0 | sizeof(struct nsm_code_auth_key_perm_query_req) - |
1100 | 0 | NSM_REQUEST_CONVENTION_LEN) { |
1101 | 0 | return NSM_SW_ERROR_DATA; |
1102 | 0 | } |
1103 | 0 | *component_classification = req->component_classification; |
1104 | 0 | *component_identifier = req->component_identifier; |
1105 | 0 | *component_classification_index = req->component_classification_index; |
1106 | |
|
1107 | 0 | return NSM_SW_SUCCESS; |
1108 | 0 | } |
1109 | | |
1110 | | int encode_nsm_code_auth_key_perm_query_req( |
1111 | | uint8_t instance_id, uint16_t component_classification, |
1112 | | uint16_t component_identifier, uint8_t component_classification_index, |
1113 | | struct nsm_msg *msg) |
1114 | 0 | { |
1115 | 0 | if (msg == NULL) { |
1116 | 0 | return NSM_SW_ERROR_NULL; |
1117 | 0 | } |
1118 | | |
1119 | 0 | struct nsm_header_info header = {0}; |
1120 | 0 | header.nsm_msg_type = NSM_REQUEST; |
1121 | 0 | header.instance_id = instance_id; |
1122 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1123 | |
|
1124 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1125 | 0 | if (rc != NSM_SUCCESS) { |
1126 | 0 | return rc; |
1127 | 0 | } |
1128 | | |
1129 | 0 | struct nsm_code_auth_key_perm_query_req *req = |
1130 | 0 | (struct nsm_code_auth_key_perm_query_req *)msg->payload; |
1131 | 0 | req->hdr.command = NSM_FW_QUERY_CODE_AUTH_KEY_PERM; |
1132 | 0 | req->hdr.data_size = |
1133 | 0 | htole16(sizeof(struct nsm_code_auth_key_perm_query_req) - |
1134 | 0 | NSM_REQUEST_CONVENTION_LEN); |
1135 | 0 | req->component_classification = component_classification; |
1136 | 0 | req->component_identifier = component_identifier; |
1137 | 0 | req->component_classification_index = component_classification_index; |
1138 | |
|
1139 | 0 | return NSM_SUCCESS; |
1140 | 0 | } |
1141 | | |
1142 | | int decode_nsm_code_auth_key_perm_query_resp( |
1143 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1144 | | uint16_t *reason_code, uint16_t *active_component_key_index, |
1145 | | uint16_t *pending_component_key_index, uint8_t *permission_bitmap_length, |
1146 | | uint8_t *active_component_key_perm_bitmap, |
1147 | | uint8_t *pending_component_key_perm_bitmap, uint8_t *efuse_key_perm_bitmap, |
1148 | | uint8_t *pending_efuse_key_perm_bitmap) |
1149 | 0 | { |
1150 | 0 | if (msg == NULL || active_component_key_index == NULL || |
1151 | 0 | pending_component_key_index == NULL || |
1152 | 0 | permission_bitmap_length == NULL) { |
1153 | 0 | return NSM_SW_ERROR_NULL; |
1154 | 0 | } |
1155 | | |
1156 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1157 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1158 | 0 | return rc; |
1159 | 0 | } |
1160 | | |
1161 | 0 | size_t expected_bitmap_length = |
1162 | 0 | msg_len - sizeof(struct nsm_msg_hdr) - |
1163 | 0 | sizeof(struct nsm_code_auth_key_perm_query_resp); |
1164 | 0 | struct nsm_code_auth_key_perm_query_resp *resp = |
1165 | 0 | (struct nsm_code_auth_key_perm_query_resp *)msg->payload; |
1166 | 0 | if (expected_bitmap_length != |
1167 | 0 | (size_t)resp->permission_bitmap_length * 4u) { |
1168 | 0 | return NSM_SW_ERROR_LENGTH; |
1169 | 0 | } |
1170 | 0 | *active_component_key_index = resp->active_component_key_index; |
1171 | 0 | *pending_component_key_index = resp->pending_component_key_index; |
1172 | 0 | *permission_bitmap_length = resp->permission_bitmap_length; |
1173 | 0 | if (active_component_key_perm_bitmap != NULL) { |
1174 | 0 | const uint8_t *bitmap_ptr = |
1175 | 0 | msg->payload + |
1176 | 0 | sizeof(struct nsm_code_auth_key_perm_query_resp); |
1177 | 0 | memcpy(active_component_key_perm_bitmap, bitmap_ptr, |
1178 | 0 | resp->permission_bitmap_length); |
1179 | 0 | } |
1180 | 0 | if (pending_component_key_perm_bitmap != NULL) { |
1181 | 0 | const uint8_t *bitmap_ptr = |
1182 | 0 | msg->payload + |
1183 | 0 | sizeof(struct nsm_code_auth_key_perm_query_resp) + |
1184 | 0 | resp->permission_bitmap_length; |
1185 | 0 | memcpy(pending_component_key_perm_bitmap, bitmap_ptr, |
1186 | 0 | resp->permission_bitmap_length); |
1187 | 0 | } |
1188 | 0 | if (efuse_key_perm_bitmap != NULL) { |
1189 | 0 | const uint8_t *bitmap_ptr = |
1190 | 0 | msg->payload + |
1191 | 0 | sizeof(struct nsm_code_auth_key_perm_query_resp) + |
1192 | 0 | resp->permission_bitmap_length * 2u; |
1193 | 0 | memcpy(efuse_key_perm_bitmap, bitmap_ptr, |
1194 | 0 | resp->permission_bitmap_length); |
1195 | 0 | } |
1196 | 0 | if (pending_efuse_key_perm_bitmap != NULL) { |
1197 | 0 | const uint8_t *bitmap_ptr = |
1198 | 0 | msg->payload + |
1199 | 0 | sizeof(struct nsm_code_auth_key_perm_query_resp) + |
1200 | 0 | resp->permission_bitmap_length * 3u; |
1201 | 0 | memcpy(pending_efuse_key_perm_bitmap, bitmap_ptr, |
1202 | 0 | resp->permission_bitmap_length); |
1203 | 0 | } |
1204 | |
|
1205 | 0 | return NSM_SW_SUCCESS; |
1206 | 0 | } |
1207 | | |
1208 | | int encode_nsm_code_auth_key_perm_query_resp( |
1209 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
1210 | | uint16_t active_component_key_index, uint16_t pending_component_key_index, |
1211 | | uint8_t permission_bitmap_length, uint8_t *active_component_key_perm_bitmap, |
1212 | | uint8_t *pending_component_key_perm_bitmap, uint8_t *efuse_key_perm_bitmap, |
1213 | | uint8_t *pending_efuse_key_perm_bitmap, struct nsm_msg *msg) |
1214 | 0 | { |
1215 | 0 | if (msg == NULL || (permission_bitmap_length != 0 && |
1216 | 0 | (active_component_key_perm_bitmap == NULL || |
1217 | 0 | pending_component_key_perm_bitmap == NULL || |
1218 | 0 | efuse_key_perm_bitmap == NULL || |
1219 | 0 | pending_efuse_key_perm_bitmap == NULL))) { |
1220 | 0 | return NSM_SW_ERROR_NULL; |
1221 | 0 | } |
1222 | | |
1223 | 0 | struct nsm_header_info header = {0}; |
1224 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
1225 | 0 | header.instance_id = instance_id; |
1226 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1227 | |
|
1228 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1229 | 0 | if (rc != NSM_SW_SUCCESS) { |
1230 | 0 | return rc; |
1231 | 0 | } |
1232 | | |
1233 | 0 | if (cc != NSM_SUCCESS) { |
1234 | 0 | return encode_reason_code(cc, reason_code, |
1235 | 0 | NSM_FW_QUERY_CODE_AUTH_KEY_PERM, msg); |
1236 | 0 | } |
1237 | | |
1238 | 0 | struct nsm_code_auth_key_perm_query_resp *resp = |
1239 | 0 | (struct nsm_code_auth_key_perm_query_resp *)msg->payload; |
1240 | 0 | resp->hdr.command = NSM_FW_QUERY_CODE_AUTH_KEY_PERM; |
1241 | 0 | resp->hdr.completion_code = cc; |
1242 | 0 | resp->hdr.data_size = |
1243 | 0 | htole16(sizeof(struct nsm_code_auth_key_perm_query_resp) - |
1244 | 0 | NSM_RESPONSE_CONVENTION_LEN) + |
1245 | 0 | permission_bitmap_length; |
1246 | 0 | resp->active_component_key_index = active_component_key_index; |
1247 | 0 | resp->pending_component_key_index = pending_component_key_index; |
1248 | 0 | resp->permission_bitmap_length = permission_bitmap_length; |
1249 | 0 | uint8_t *bitmap_ptr = |
1250 | 0 | msg->payload + sizeof(struct nsm_code_auth_key_perm_query_resp); |
1251 | 0 | memcpy(bitmap_ptr, active_component_key_perm_bitmap, |
1252 | 0 | permission_bitmap_length); |
1253 | 0 | bitmap_ptr += permission_bitmap_length; |
1254 | 0 | memcpy(bitmap_ptr, pending_component_key_perm_bitmap, |
1255 | 0 | permission_bitmap_length); |
1256 | 0 | bitmap_ptr += permission_bitmap_length; |
1257 | 0 | memcpy(bitmap_ptr, efuse_key_perm_bitmap, permission_bitmap_length); |
1258 | 0 | bitmap_ptr += permission_bitmap_length; |
1259 | 0 | memcpy(bitmap_ptr, pending_efuse_key_perm_bitmap, |
1260 | 0 | permission_bitmap_length); |
1261 | |
|
1262 | 0 | return NSM_SW_SUCCESS; |
1263 | 0 | } |
1264 | | |
1265 | | int decode_nsm_code_auth_key_perm_update_req( |
1266 | | const struct nsm_msg *msg, size_t msg_len, |
1267 | | enum nsm_code_auth_key_perm_request_type *request_type, |
1268 | | uint16_t *component_classification, uint16_t *component_identifier, |
1269 | | uint8_t *component_classification_index, uint64_t *nonce, |
1270 | | uint8_t *permission_bitmap_length, uint8_t *permission_bitmap) |
1271 | 0 | { |
1272 | 0 | if (msg == NULL || request_type == NULL || |
1273 | 0 | component_classification == NULL || component_identifier == NULL || |
1274 | 0 | component_classification_index == NULL || nonce == NULL || |
1275 | 0 | permission_bitmap_length == NULL) { |
1276 | 0 | return NSM_SW_ERROR_NULL; |
1277 | 0 | } |
1278 | | |
1279 | 0 | size_t expected_bitmap_length = |
1280 | 0 | msg_len - sizeof(struct nsm_msg_hdr) - |
1281 | 0 | sizeof(struct nsm_code_auth_key_perm_update_req); |
1282 | 0 | struct nsm_code_auth_key_perm_update_req *req = |
1283 | 0 | (struct nsm_code_auth_key_perm_update_req *)msg->payload; |
1284 | 0 | if (expected_bitmap_length != req->permission_bitmap_length) { |
1285 | 0 | return NSM_SW_ERROR_LENGTH; |
1286 | 0 | } |
1287 | 0 | if (req->request_type != |
1288 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE && |
1289 | 0 | req->request_type != |
1290 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_SPECIFIED_VALUE) { |
1291 | 0 | return NSM_SW_ERROR_DATA; |
1292 | 0 | } |
1293 | 0 | *request_type = req->request_type; |
1294 | 0 | *component_classification = req->component_classification; |
1295 | 0 | *component_identifier = req->component_identifier; |
1296 | 0 | *component_classification_index = req->component_classification_index; |
1297 | 0 | *nonce = req->nonce; |
1298 | 0 | *permission_bitmap_length = req->permission_bitmap_length; |
1299 | 0 | if (permission_bitmap != NULL) { |
1300 | 0 | const uint8_t *bitmap_ptr = |
1301 | 0 | msg->payload + |
1302 | 0 | sizeof(struct nsm_code_auth_key_perm_update_req); |
1303 | 0 | memcpy(permission_bitmap, bitmap_ptr, expected_bitmap_length); |
1304 | 0 | } |
1305 | |
|
1306 | 0 | return NSM_SW_SUCCESS; |
1307 | 0 | } |
1308 | | |
1309 | | int encode_nsm_code_auth_key_perm_update_req( |
1310 | | uint8_t instance_id, enum nsm_code_auth_key_perm_request_type request_type, |
1311 | | uint16_t component_classification, uint16_t component_identifier, |
1312 | | uint8_t component_classification_index, uint64_t nonce, |
1313 | | uint8_t permission_bitmap_length, uint8_t *permission_bitmap, |
1314 | | struct nsm_msg *msg) |
1315 | 0 | { |
1316 | 0 | if (msg == NULL) { |
1317 | 0 | return NSM_SW_ERROR_NULL; |
1318 | 0 | } |
1319 | 0 | if (request_type != |
1320 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE && |
1321 | 0 | request_type != |
1322 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_SPECIFIED_VALUE) { |
1323 | 0 | return NSM_SW_ERROR_DATA; |
1324 | 0 | } |
1325 | 0 | if (request_type == |
1326 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE && |
1327 | 0 | permission_bitmap_length != 0) { |
1328 | 0 | return NSM_SW_ERROR_DATA; |
1329 | 0 | } |
1330 | 0 | if (request_type == |
1331 | 0 | NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_SPECIFIED_VALUE && |
1332 | 0 | (permission_bitmap_length == 0 || permission_bitmap == NULL)) { |
1333 | 0 | return NSM_SW_ERROR_DATA; |
1334 | 0 | } |
1335 | | |
1336 | 0 | struct nsm_header_info header = {0}; |
1337 | 0 | header.nsm_msg_type = NSM_REQUEST; |
1338 | 0 | header.instance_id = instance_id; |
1339 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1340 | |
|
1341 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1342 | 0 | if (rc != NSM_SUCCESS) { |
1343 | 0 | return rc; |
1344 | 0 | } |
1345 | | |
1346 | 0 | struct nsm_code_auth_key_perm_update_req *req = |
1347 | 0 | (struct nsm_code_auth_key_perm_update_req *)msg->payload; |
1348 | 0 | req->hdr.command = NSM_FW_UPDATE_CODE_AUTH_KEY_PERM; |
1349 | 0 | req->hdr.data_size = |
1350 | 0 | htole16(sizeof(struct nsm_code_auth_key_perm_update_req) - |
1351 | 0 | NSM_REQUEST_CONVENTION_LEN + permission_bitmap_length); |
1352 | 0 | req->request_type = request_type; |
1353 | 0 | req->component_classification = component_classification; |
1354 | 0 | req->component_identifier = component_identifier; |
1355 | 0 | req->component_classification_index = component_classification_index; |
1356 | 0 | req->nonce = nonce; |
1357 | 0 | req->permission_bitmap_length = permission_bitmap_length; |
1358 | 0 | if (permission_bitmap_length != 0) { |
1359 | 0 | uint8_t *bitmap_ptr = |
1360 | 0 | msg->payload + |
1361 | 0 | sizeof(struct nsm_code_auth_key_perm_update_req); |
1362 | 0 | memcpy(bitmap_ptr, permission_bitmap, permission_bitmap_length); |
1363 | 0 | } |
1364 | |
|
1365 | 0 | return NSM_SUCCESS; |
1366 | 0 | } |
1367 | | |
1368 | | int decode_nsm_code_auth_key_perm_update_resp(const struct nsm_msg *msg, |
1369 | | size_t msg_len, uint8_t *cc, |
1370 | | uint16_t *reason_code, |
1371 | | uint32_t *update_method) |
1372 | 0 | { |
1373 | 0 | if (msg == NULL || update_method == NULL) { |
1374 | 0 | return NSM_SW_ERROR_NULL; |
1375 | 0 | } |
1376 | | |
1377 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1378 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1379 | 0 | return rc; |
1380 | 0 | } |
1381 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
1382 | 0 | sizeof(struct nsm_code_auth_key_perm_update_resp)) { |
1383 | 0 | return NSM_SW_ERROR_LENGTH; |
1384 | 0 | } |
1385 | | |
1386 | 0 | struct nsm_code_auth_key_perm_update_resp *resp = |
1387 | 0 | (struct nsm_code_auth_key_perm_update_resp *)msg->payload; |
1388 | 0 | if (resp->hdr.data_size < |
1389 | 0 | sizeof(struct nsm_code_auth_key_perm_update_resp) - |
1390 | 0 | NSM_RESPONSE_CONVENTION_LEN) { |
1391 | 0 | return NSM_SW_ERROR_DATA; |
1392 | 0 | } |
1393 | 0 | *update_method = resp->update_method; |
1394 | |
|
1395 | 0 | return NSM_SW_SUCCESS; |
1396 | 0 | } |
1397 | | |
1398 | | int encode_nsm_code_auth_key_perm_update_resp(uint8_t instance_id, uint8_t cc, |
1399 | | uint16_t reason_code, |
1400 | | uint32_t update_method, |
1401 | | struct nsm_msg *msg) |
1402 | 0 | { |
1403 | 0 | if (msg == NULL) { |
1404 | 0 | return NSM_SW_ERROR_NULL; |
1405 | 0 | } |
1406 | | |
1407 | 0 | struct nsm_header_info header = {0}; |
1408 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
1409 | 0 | header.instance_id = instance_id; |
1410 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1411 | |
|
1412 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1413 | 0 | if (rc != NSM_SW_SUCCESS) { |
1414 | 0 | return rc; |
1415 | 0 | } |
1416 | | |
1417 | 0 | if (cc != NSM_SUCCESS) { |
1418 | 0 | return encode_reason_code( |
1419 | 0 | cc, reason_code, NSM_FW_UPDATE_CODE_AUTH_KEY_PERM, msg); |
1420 | 0 | } |
1421 | | |
1422 | 0 | struct nsm_code_auth_key_perm_update_resp *resp = |
1423 | 0 | (struct nsm_code_auth_key_perm_update_resp *)msg->payload; |
1424 | 0 | resp->hdr.command = NSM_FW_UPDATE_CODE_AUTH_KEY_PERM; |
1425 | 0 | resp->hdr.completion_code = cc; |
1426 | 0 | resp->hdr.data_size = |
1427 | 0 | htole16(sizeof(struct nsm_code_auth_key_perm_update_resp) - |
1428 | 0 | NSM_RESPONSE_CONVENTION_LEN); |
1429 | 0 | resp->update_method = update_method; |
1430 | |
|
1431 | 0 | return NSM_SW_SUCCESS; |
1432 | 0 | } |
1433 | | |
1434 | | int encode_nsm_query_firmware_security_version_number_req( |
1435 | | uint8_t instance_id, |
1436 | | const struct nsm_firmware_security_version_number_req *fw_req, |
1437 | | struct nsm_msg *msg) |
1438 | 0 | { |
1439 | 0 | if (msg == NULL) { |
1440 | 0 | return NSM_SW_ERROR_NULL; |
1441 | 0 | } |
1442 | 0 | struct nsm_header_info header = {0}; |
1443 | 0 | header.nsm_msg_type = NSM_REQUEST; |
1444 | 0 | header.instance_id = instance_id; |
1445 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1446 | |
|
1447 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1448 | 0 | if (rc != NSM_SUCCESS) { |
1449 | 0 | return rc; |
1450 | 0 | } |
1451 | | |
1452 | 0 | struct nsm_firmware_security_version_number_req_command *request = |
1453 | 0 | (struct nsm_firmware_security_version_number_req_command *) |
1454 | 0 | msg->payload; |
1455 | 0 | request->hdr.command = NSM_FW_QUERY_MIN_SECURITY_VERSION_NUMBER; |
1456 | 0 | request->hdr.data_size = |
1457 | 0 | sizeof(struct nsm_firmware_security_version_number_req); |
1458 | 0 | memcpy(&request->fq_req, fw_req, |
1459 | 0 | sizeof(struct nsm_firmware_security_version_number_req)); |
1460 | |
|
1461 | 0 | return NSM_SW_SUCCESS; |
1462 | 0 | } |
1463 | | |
1464 | | int decode_nsm_query_firmware_security_version_number_req( |
1465 | | const struct nsm_msg *msg, size_t msg_len, |
1466 | | struct nsm_firmware_security_version_number_req *fw_req) |
1467 | 0 | { |
1468 | 0 | if (msg == NULL || fw_req == NULL) { |
1469 | 0 | return NSM_SW_ERROR_NULL; |
1470 | 0 | } |
1471 | | |
1472 | 0 | if (msg_len < |
1473 | 0 | sizeof(struct nsm_msg_hdr) + |
1474 | 0 | sizeof( |
1475 | 0 | struct nsm_firmware_security_version_number_req_command)) { |
1476 | 0 | return NSM_SW_ERROR_LENGTH; |
1477 | 0 | } |
1478 | | |
1479 | 0 | struct nsm_firmware_security_version_number_req_command *request = |
1480 | 0 | (struct nsm_firmware_security_version_number_req_command *) |
1481 | 0 | msg->payload; |
1482 | 0 | if (request->hdr.data_size < sizeof(*fw_req)) { |
1483 | 0 | return NSM_SW_ERROR_DATA; |
1484 | 0 | } |
1485 | | |
1486 | 0 | *fw_req = request->fq_req; |
1487 | |
|
1488 | 0 | return NSM_SW_SUCCESS; |
1489 | 0 | } |
1490 | | |
1491 | | int encode_nsm_query_firmware_security_version_number_resp( |
1492 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
1493 | | struct nsm_firmware_security_version_number_resp *sec_info, |
1494 | | struct nsm_msg *msg) |
1495 | 0 | { |
1496 | 0 | if (msg == NULL) { |
1497 | 0 | return NSM_SW_ERROR_NULL; |
1498 | 0 | } |
1499 | | |
1500 | 0 | struct nsm_header_info header = {0}; |
1501 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
1502 | 0 | header.instance_id = instance_id; |
1503 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1504 | |
|
1505 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1506 | 0 | if (rc != NSM_SW_SUCCESS) { |
1507 | 0 | return rc; |
1508 | 0 | } |
1509 | | |
1510 | 0 | if (cc != NSM_SUCCESS) { |
1511 | 0 | return encode_reason_code( |
1512 | 0 | cc, reason_code, NSM_FW_QUERY_MIN_SECURITY_VERSION_NUMBER, |
1513 | 0 | msg); |
1514 | 0 | } |
1515 | | |
1516 | 0 | struct nsm_firmware_security_version_number_resp_command *response = |
1517 | 0 | (struct nsm_firmware_security_version_number_resp_command *) |
1518 | 0 | msg->payload; |
1519 | 0 | response->hdr.command = NSM_FW_QUERY_MIN_SECURITY_VERSION_NUMBER; |
1520 | 0 | response->hdr.completion_code = cc; |
1521 | |
|
1522 | 0 | uint16_t msg_size = |
1523 | 0 | sizeof(struct nsm_common_resp) + |
1524 | 0 | sizeof(struct nsm_firmware_security_version_number_resp); |
1525 | |
|
1526 | 0 | response->hdr.data_size = htole16(msg_size); |
1527 | |
|
1528 | 0 | memcpy(&(response->sec_ver_resp), sec_info, |
1529 | 0 | sizeof(struct nsm_firmware_security_version_number_resp)); |
1530 | |
|
1531 | 0 | return NSM_SW_SUCCESS; |
1532 | 0 | } |
1533 | | |
1534 | | int decode_nsm_query_firmware_security_version_number_resp( |
1535 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1536 | | uint16_t *reason_code, |
1537 | | struct nsm_firmware_security_version_number_resp *sec_resp) |
1538 | 0 | { |
1539 | 0 | if (msg == NULL || sec_resp == NULL) { |
1540 | 0 | return NSM_SW_ERROR_NULL; |
1541 | 0 | } |
1542 | | |
1543 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1544 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1545 | 0 | return rc; |
1546 | 0 | } |
1547 | | |
1548 | 0 | if (msg_len < |
1549 | 0 | sizeof(struct nsm_msg_hdr) + |
1550 | 0 | sizeof( |
1551 | 0 | struct nsm_firmware_security_version_number_resp_command)) { |
1552 | 0 | return NSM_SW_ERROR_LENGTH; |
1553 | 0 | } |
1554 | | |
1555 | 0 | struct nsm_firmware_security_version_number_resp_command *resp = |
1556 | 0 | (struct nsm_firmware_security_version_number_resp_command *) |
1557 | 0 | msg->payload; |
1558 | |
|
1559 | 0 | memcpy(sec_resp, &(resp->sec_ver_resp), |
1560 | 0 | sizeof(struct nsm_firmware_security_version_number_resp)); |
1561 | |
|
1562 | 0 | return NSM_SW_SUCCESS; |
1563 | 0 | } |
1564 | | |
1565 | | int encode_nsm_firmware_update_sec_ver_req( |
1566 | | uint8_t instance_id, |
1567 | | const struct nsm_firmware_update_min_sec_ver_req *fw_req, |
1568 | | struct nsm_msg *msg) |
1569 | 0 | { |
1570 | 0 | if (msg == NULL) { |
1571 | 0 | return NSM_SW_ERROR_NULL; |
1572 | 0 | } |
1573 | 0 | struct nsm_header_info header = {0}; |
1574 | 0 | header.nsm_msg_type = NSM_REQUEST; |
1575 | 0 | header.instance_id = instance_id; |
1576 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1577 | |
|
1578 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1579 | 0 | if (rc != NSM_SUCCESS) { |
1580 | 0 | return rc; |
1581 | 0 | } |
1582 | | |
1583 | 0 | struct nsm_firmware_update_min_sec_ver_req_command *request = |
1584 | 0 | (struct nsm_firmware_update_min_sec_ver_req_command *)msg->payload; |
1585 | 0 | request->hdr.command = NSM_FW_UPDATE_MIN_SECURITY_VERSION_NUMBER; |
1586 | 0 | request->hdr.data_size = |
1587 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_req); |
1588 | 0 | memcpy(&request->ver_update_req, fw_req, |
1589 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_req)); |
1590 | |
|
1591 | 0 | return NSM_SW_SUCCESS; |
1592 | 0 | } |
1593 | | |
1594 | | int decode_nsm_firmware_update_sec_ver_req( |
1595 | | const struct nsm_msg *msg, size_t msg_len, |
1596 | | struct nsm_firmware_update_min_sec_ver_req *fw_req) |
1597 | 0 | { |
1598 | 0 | if (msg == NULL || fw_req == NULL) { |
1599 | 0 | return NSM_SW_ERROR_NULL; |
1600 | 0 | } |
1601 | | |
1602 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
1603 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_req)) { |
1604 | 0 | return NSM_SW_ERROR_LENGTH; |
1605 | 0 | } |
1606 | | |
1607 | 0 | struct nsm_firmware_update_min_sec_ver_req_command *request = |
1608 | 0 | (struct nsm_firmware_update_min_sec_ver_req_command *)msg->payload; |
1609 | 0 | if (request->hdr.data_size < sizeof(*fw_req)) { |
1610 | 0 | return NSM_SW_ERROR_DATA; |
1611 | 0 | } |
1612 | | |
1613 | 0 | *fw_req = request->ver_update_req; |
1614 | |
|
1615 | 0 | return NSM_SW_SUCCESS; |
1616 | 0 | } |
1617 | | |
1618 | | int encode_nsm_firmware_update_sec_ver_resp( |
1619 | | uint8_t instance_id, uint8_t cc, uint16_t reason_code, |
1620 | | struct nsm_firmware_update_min_sec_ver_resp *sec_resp, struct nsm_msg *msg) |
1621 | 0 | { |
1622 | 0 | if (msg == NULL) { |
1623 | 0 | return NSM_SW_ERROR_NULL; |
1624 | 0 | } |
1625 | | |
1626 | 0 | struct nsm_header_info header = {0}; |
1627 | 0 | header.nsm_msg_type = NSM_RESPONSE; |
1628 | 0 | header.instance_id = instance_id; |
1629 | 0 | header.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
1630 | |
|
1631 | 0 | uint8_t rc = pack_nsm_header(&header, &msg->hdr); |
1632 | 0 | if (rc != NSM_SW_SUCCESS) { |
1633 | 0 | return rc; |
1634 | 0 | } |
1635 | | |
1636 | 0 | if (cc != NSM_SUCCESS) { |
1637 | 0 | return encode_reason_code( |
1638 | 0 | cc, reason_code, NSM_FW_UPDATE_MIN_SECURITY_VERSION_NUMBER, |
1639 | 0 | msg); |
1640 | 0 | } |
1641 | | |
1642 | 0 | struct nsm_firmware_update_min_sec_ver_resp_command *response = |
1643 | 0 | (struct nsm_firmware_update_min_sec_ver_resp_command *)msg->payload; |
1644 | 0 | response->hdr.command = NSM_FW_UPDATE_MIN_SECURITY_VERSION_NUMBER; |
1645 | 0 | response->hdr.completion_code = cc; |
1646 | |
|
1647 | 0 | uint16_t msg_size = sizeof(struct nsm_common_resp) + |
1648 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_resp); |
1649 | |
|
1650 | 0 | response->hdr.data_size = htole16(msg_size); |
1651 | |
|
1652 | 0 | memcpy(&(response->sec_ver_resp), sec_resp, |
1653 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_resp)); |
1654 | |
|
1655 | 0 | return NSM_SW_SUCCESS; |
1656 | 0 | } |
1657 | | |
1658 | | int decode_nsm_firmware_update_sec_ver_resp( |
1659 | | const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, |
1660 | | uint16_t *reason_code, |
1661 | | struct nsm_firmware_update_min_sec_ver_resp *sec_resp) |
1662 | 0 | { |
1663 | 0 | if (msg == NULL || sec_resp == NULL) { |
1664 | 0 | return NSM_SW_ERROR_NULL; |
1665 | 0 | } |
1666 | | |
1667 | 0 | int rc = decode_reason_code_and_cc(msg, msg_len, cc, reason_code); |
1668 | 0 | if (rc != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) { |
1669 | 0 | return rc; |
1670 | 0 | } |
1671 | | |
1672 | 0 | if (msg_len < sizeof(struct nsm_msg_hdr) + |
1673 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_resp)) { |
1674 | 0 | return NSM_SW_ERROR_LENGTH; |
1675 | 0 | } |
1676 | | |
1677 | 0 | struct nsm_firmware_update_min_sec_ver_resp_command *resp = |
1678 | 0 | (struct nsm_firmware_update_min_sec_ver_resp_command *)msg->payload; |
1679 | |
|
1680 | 0 | memcpy(sec_resp, &(resp->sec_ver_resp), |
1681 | 0 | sizeof(struct nsm_firmware_update_min_sec_ver_resp)); |
1682 | |
|
1683 | 0 | return NSM_SW_SUCCESS; |
1684 | 0 | } |