blob: 0b826a86e7e1036b0089d64da238d59366aa5eab [file] [log] [blame]
Maulik Patelad2f3db2023-05-17 15:41:36 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "dpe_context_mngr.h"
9#include <assert.h>
10#include <string.h>
11#include "dice_protection_environment.h"
Maulik Patel58595d32023-06-22 10:08:53 +010012#include "dpe_crypto_interface.h"
Maulik Patelad2f3db2023-05-17 15:41:36 +010013#include "dpe_log.h"
14#include "psa/crypto.h"
15
Maulik Patel58595d32023-06-22 10:08:53 +010016#ifdef TFM_S_REG_TEST
17#define TEST_ROT_CDI_VAL { \
18 0xD2, 0x90, 0x66, 0x07, 0x2A, 0x2D, 0x2A, 0x00, \
19 0x91, 0x9D, 0xD9, 0x15, 0x14, 0xBE, 0x2D, 0xCC, \
20 0xA3, 0x9F, 0xDE, 0xC3, 0x35, 0x75, 0x84, 0x6E, \
21 0x4C, 0xB9, 0x28, 0xAC, 0x7A, 0x4E, 0X00, 0x7F \
22 }
23#endif /* TFM_S_REG_TEST */
24
25#define CONTEXT_DATA_MAX_SIZE sizeof(struct component_context_data_t)
26
Maulik Patelad2f3db2023-05-17 15:41:36 +010027static struct component_context_t component_ctx_array[MAX_NUM_OF_COMPONENTS];
28static struct layer_context_t layer_ctx_array[MAX_NUM_OF_LAYERS];
29
30static int get_free_component_context_index(void)
31{
32 int i;
33
34 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
35 if (!component_ctx_array[i].in_use) {
36 break;
37 }
38 }
39
40 if (i >= MAX_NUM_OF_COMPONENTS) {
41 /* No free index left in the array -- all used up! */
42 return -1;
43 }
44
45 return i;
46}
47
48static inline void invalidate_handle(int *handle)
49{
50 *handle = INVALID_HANDLE;
51}
52
53static dpe_error_t renew_nonce(int *handle)
54{
55 uint16_t nonce;
56
57 psa_status_t status = psa_generate_random((uint8_t *)&nonce, sizeof(nonce));
58 if (status != PSA_SUCCESS) {
59 return DPE_INTERNAL_ERROR;
60 }
61 *handle = SET_NONCE(*handle, nonce);
62
63 return DPE_NO_ERROR;
64}
65
66static dpe_error_t generate_new_handle(int *out_handle)
67{
68 /* Find the free component array element */
69 int free_component_idx = get_free_component_context_index();
70 if (free_component_idx < 0) {
71 return DPE_INSUFFICIENT_MEMORY;
72 }
73
74 *out_handle = SET_IDX(*out_handle, free_component_idx);
75
76 return renew_nonce(out_handle);
77}
78
79static void set_context_to_default(int i)
80{
81 component_ctx_array[i].in_use = false;
82 component_ctx_array[i].is_leaf = false;
83 component_ctx_array[i].nonce = INVALID_NONCE_VALUE;
84 component_ctx_array[i].parent_idx = INVALID_COMPONENT_IDX;
85 component_ctx_array[i].linked_layer_idx = INVALID_LAYER_IDX;
86 (void)memset(&component_ctx_array[i].data, 0, sizeof(struct component_context_data_t));
87 //TODO: Question: how to initialise MHU Id mapping?
88 /* Allow component to be derived by default */
89}
90
91static void invalidate_layer(int i)
92{
93 layer_ctx_array[i].state = LAYER_STATE_CLOSED;
94 layer_ctx_array[i].parent_layer_idx = INVALID_LAYER_IDX;
Maulik Patel58595d32023-06-22 10:08:53 +010095 (void)psa_destroy_key(layer_ctx_array[i].data.cdi_key_id);
96 (void)psa_destroy_key(layer_ctx_array[i].data.attest_key_id);
Maulik Patelad2f3db2023-05-17 15:41:36 +010097 (void)memset(&layer_ctx_array[i].data, 0, sizeof(struct layer_context_data_t));
98}
99
100void initialise_all_dpe_contexts(void)
101{
102 int i;
103
104 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
105 set_context_to_default(i);
106 }
107
108 for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
109 invalidate_layer(i);
110 }
111}
112
113static dpe_error_t copy_dice_input(struct component_context_t *dest_ctx,
114 const DiceInputValues *dice_inputs)
115{
116 size_t hash_len;
117 psa_status_t status;
118
119 memcpy(&dest_ctx->data.measurement_value, dice_inputs->code_hash,
120 DICE_HASH_SIZE);
121 memcpy(&dest_ctx->data.measurement_descriptor,
122 dice_inputs->code_descriptor,
123 dice_inputs->code_descriptor_size);
124
125 dest_ctx->data.measurement_descriptor_size =
126 dice_inputs->code_descriptor_size;
127
128 memcpy(&dest_ctx->data.signer_id, dice_inputs->authority_hash, DICE_HASH_SIZE);
129 memcpy(&dest_ctx->data.signer_id_descriptor,
130 dice_inputs->authority_descriptor,
131 dice_inputs->authority_descriptor_size);
132
133 dest_ctx->data.signer_id_descriptor_size =
134 dice_inputs->authority_descriptor_size;
135
136 if (dice_inputs->config_type == kDiceConfigTypeInline) {
137 /* Copy config_value */
138 memcpy(&dest_ctx->data.config_value, dice_inputs->config_value,
139 DICE_INLINE_CONFIG_SIZE);
140
141 } else {
142 /* Copy config descriptor */
143 memcpy(&dest_ctx->data.config_descriptor, dice_inputs->config_descriptor,
144 dice_inputs->config_descriptor_size);
145 dest_ctx->data.config_descriptor_size = dice_inputs->config_descriptor_size;
146
147 /* Calculate config value as hash of input config descriptor */
148 status = psa_hash_compute(PSA_ALG_SHA_256,
149 dice_inputs->config_descriptor,
150 dice_inputs->config_descriptor_size,
151 dest_ctx->data.config_value,
152 sizeof(dest_ctx->data.config_value),
153 &hash_len);
154
155 if (status != PSA_SUCCESS) {
156 return DPE_INTERNAL_ERROR;
157 }
158 }
159
160 dest_ctx->data.mode = dice_inputs->mode;
161 memcpy(&dest_ctx->data.hidden, dice_inputs->hidden, DICE_HIDDEN_SIZE);
162
163 return DPE_NO_ERROR;
164}
165
166static bool is_dice_input_valid(const DiceInputValues *dice_inputs)
167{
168 if ((dice_inputs->code_descriptor_size > DICE_CODE_DESCRIPTOR_MAX_SIZE) ||
169 (dice_inputs->authority_descriptor_size > DICE_AUTHORITY_DESCRIPTOR_MAX_SIZE) ||
170 (dice_inputs->config_descriptor_size > DICE_CONFIG_DESCRIPTOR_MAX_SIZE)) {
171 return false;
172 }
173
174 return true;
175}
176
177static bool is_input_handle_valid(int input_context_handle)
178{
179 uint16_t idx = GET_IDX(input_context_handle);
180 uint16_t nonce = GET_NONCE(input_context_handle);
181
182 /* Validate input handle id and nonce */
183 if ((idx >= MAX_NUM_OF_COMPONENTS) || (nonce == INVALID_NONCE_VALUE)) {
184 return false;
185 }
186
187 if (nonce == component_ctx_array[idx].nonce) {
188 return true;
189 }
190
191 return false;
192}
193
Maulik Patel58595d32023-06-22 10:08:53 +0100194/* Attest_CDI Input requires {measurement_value, config, authority, mode, hidden} in
195 * same order
196 */
197static psa_status_t get_component_data_for_attest_cdi(uint8_t *dest_buf,
198 size_t max_size,
199 size_t *dest_size,
200 const struct component_context_t *comp_ctx)
Maulik Patelad2f3db2023-05-17 15:41:36 +0100201{
Maulik Patel58595d32023-06-22 10:08:53 +0100202 size_t out_size = 0;
203
204 if ((DICE_HASH_SIZE + DICE_INLINE_CONFIG_SIZE + DICE_HASH_SIZE +
205 sizeof(comp_ctx->data.mode) + DICE_HIDDEN_SIZE > max_size )) {
206 return PSA_ERROR_BUFFER_TOO_SMALL;
207 }
208
209 memcpy(&dest_buf[out_size], comp_ctx->data.measurement_value, DICE_HASH_SIZE);
210 out_size += DICE_HASH_SIZE;
211
212 memcpy(&dest_buf[out_size], comp_ctx->data.config_value, DICE_INLINE_CONFIG_SIZE);
213 out_size += DICE_INLINE_CONFIG_SIZE;
214
215 memcpy(&dest_buf[out_size], comp_ctx->data.signer_id, DICE_HASH_SIZE);
216 out_size += DICE_HASH_SIZE;
217
218 memcpy(&dest_buf[out_size], &comp_ctx->data.mode, sizeof(comp_ctx->data.mode));
219 out_size += sizeof(comp_ctx->data.mode);
220
221 memcpy(&dest_buf[out_size], comp_ctx->data.hidden, DICE_HIDDEN_SIZE);
222 out_size += DICE_HIDDEN_SIZE;
223
224 *dest_size = out_size;
225
226 return PSA_SUCCESS;
227}
228
229static psa_status_t compute_layer_cdi_attest_input(uint16_t curr_layer_idx)
230{
231 psa_status_t status;
232 uint8_t component_ctx_data[CONTEXT_DATA_MAX_SIZE];
233 size_t ctx_data_size, hash_len;
234 int idx;
235
236 psa_hash_operation_t hash_op = psa_hash_operation_init();
237 status = psa_hash_setup(&hash_op, DPE_HASH_ALG);
238 if (status != PSA_SUCCESS) {
239 return status;
240 }
241
242 //TODO:
243 /* How to combine measurements of multiple SW components into a single hash
244 * is not yet defined by the Open DICE profile. This implementation
245 * concatenates the data of all SW components which belong to the same layer
246 * and hash it.
247 */
248 for (idx = 0; idx < MAX_NUM_OF_COMPONENTS; idx++) {
249 if (component_ctx_array[idx].linked_layer_idx == curr_layer_idx) {
250 /* This component belongs to current layer */
251 /* Concatenate all context data for this component */
252 status = get_component_data_for_attest_cdi(component_ctx_data,
253 sizeof(component_ctx_data),
254 &ctx_data_size,
255 &component_ctx_array[idx]);
256 if (status != PSA_SUCCESS) {
257 return status;
258 }
259
260 status = psa_hash_update(&hash_op,
261 component_ctx_data,
262 ctx_data_size);
263 if (status != PSA_SUCCESS) {
264 return status;
265 }
266 }
267 }
268
269 status = psa_hash_finish(&hash_op,
270 &layer_ctx_array[curr_layer_idx].attest_cdi_hash_input[0],
271 sizeof(layer_ctx_array[curr_layer_idx].attest_cdi_hash_input),
272 &hash_len);
273
274 assert(hash_len == DPE_HASH_ALG_SIZE);
275
276 return status;
277}
278
279static dpe_error_t derive_child_create_certificate(uint16_t layer_idx)
280{
281 uint16_t parent_idx;
282 psa_status_t status;
283
284 assert(layer_idx < MAX_NUM_OF_LAYERS);
Maulik Patelad2f3db2023-05-17 15:41:36 +0100285 /* Finalise the layer */
Maulik Patel58595d32023-06-22 10:08:53 +0100286 layer_ctx_array[layer_idx].state = LAYER_STATE_FINALISED;
287
288 /* For RoT Layer, CDI values are calculated by BL1_1 */
289 if (layer_idx != DPE_ROT_LAYER_IDX) {
290
291 parent_idx = layer_ctx_array[layer_idx].parent_layer_idx;
292 assert(parent_idx < MAX_NUM_OF_LAYERS);
293
294 status = compute_layer_cdi_attest_input(layer_idx);
295 if (status != PSA_SUCCESS) {
296 return DPE_INTERNAL_ERROR;
297 }
298
299 status = derive_attestation_cdi(&layer_ctx_array[layer_idx],
300 &layer_ctx_array[parent_idx]);
301 if (status != PSA_SUCCESS) {
302 return DPE_INTERNAL_ERROR;
303 }
304
305 status = derive_sealing_cdi(&layer_ctx_array[layer_idx]);
306 if (status != PSA_SUCCESS) {
307 return DPE_INTERNAL_ERROR;
308 }
309 }
310
311 status = derive_wrapping_key(&layer_ctx_array[layer_idx]);
312 if (status != PSA_SUCCESS) {
313 return DPE_INTERNAL_ERROR;
314 }
315
316 status = derive_attestation_key(&layer_ctx_array[layer_idx]);
317 if (status != PSA_SUCCESS) {
318 return DPE_INTERNAL_ERROR;
319 }
320
321 status = create_layer_certificate(&layer_ctx_array[layer_idx]);
322 if (status != PSA_SUCCESS) {
323 return DPE_INTERNAL_ERROR;
324 }
325
326 status = store_layer_certificate(&layer_ctx_array[layer_idx]);
327 if (status != PSA_SUCCESS) {
328 return DPE_INTERNAL_ERROR;
329 }
330
Maulik Patelad2f3db2023-05-17 15:41:36 +0100331 return DPE_NO_ERROR;
332}
333
334static uint16_t open_new_layer(void)
335{
336 int i;
337
338 for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
339 if (layer_ctx_array[i].state == LAYER_STATE_CLOSED) {
340 layer_ctx_array[i].state = LAYER_STATE_OPEN;
341 return i;
342 }
343 }
344
345 return INVALID_LAYER_IDX;
346}
347
348static inline void link_layer(uint16_t child_layer, uint16_t parent_layer)
349{
350 layer_ctx_array[child_layer].parent_layer_idx = parent_layer;
351}
352
353dpe_error_t derive_rot_context(const DiceInputValues *dice_inputs,
354 int *new_child_ctx_handle,
355 int *new_parent_ctx_handle)
356{
357 int status;
358 struct component_context_t *child_comp_ctx, *new_child_ctx;
359 uint16_t new_layer_idx;
360
361 log_derive_rot_context(dice_inputs);
362
363 /* Validate dice inputs */
364 if (!is_dice_input_valid(dice_inputs)) {
365 return DPE_INVALID_ARGUMENT;
366 }
367
368 child_comp_ctx = &component_ctx_array[0];
369 status = copy_dice_input(child_comp_ctx, dice_inputs);
370 if (status != DPE_NO_ERROR) {
371 return status;
372 }
373
374 child_comp_ctx->in_use = true;
375 /* Link context to RoT Layer */
376 child_comp_ctx->linked_layer_idx = DPE_ROT_LAYER_IDX;
377 /* Parent is same as child for RoT context */
378 child_comp_ctx->parent_idx = 0;
379 /* Parent not deriving any more children */
380 invalidate_handle(new_parent_ctx_handle);
381
382 //TODO: Update expected_mhu_id of derived child
383 /* Create certificate for RoT layer */
384 status = derive_child_create_certificate(DPE_ROT_LAYER_IDX);
385 if (status != DPE_NO_ERROR) {
386 return status;
387 }
388
389 /* Generate new handle for child for subsequent requests */
390 if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
391 return DPE_INTERNAL_ERROR;
392 }
393
394 /* Update the component context array element as pointed by newly generated handle */
395 new_child_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
396 new_child_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
397 new_child_ctx->in_use = true;
398 /* New child's parent is current RoT component which is evaluated as 0 */
399 new_child_ctx->parent_idx = 0;
400
401 /* Open new layer since RoT layer is finalised and
402 * link the new child to this new layer
403 */
404 new_layer_idx = open_new_layer();
405 new_child_ctx->linked_layer_idx = new_layer_idx;
406
407 /* Link this new layer to the RoT Layer */
408 link_layer(new_layer_idx, DPE_ROT_LAYER_IDX);
409
410 return DPE_NO_ERROR;
411}
412
413static inline bool is_input_client_id_valid(int32_t client_id)
414{
415 //TODO: Waiting for implementation
416 return true;
417}
418
419static void assign_layer_to_context(struct component_context_t *new_ctx)
420{
421 uint16_t new_layer_idx, parent_layer_idx;
422
423 assert(new_ctx->parent_idx < MAX_NUM_OF_COMPONENTS);
424
425 parent_layer_idx = component_ctx_array[new_ctx->parent_idx].linked_layer_idx;
426 assert(parent_layer_idx < MAX_NUM_OF_LAYERS);
427
428 if (layer_ctx_array[parent_layer_idx].state == LAYER_STATE_FINALISED) {
429 /* Parent comp's layer of new child is finalised; open a new layer */
430 new_layer_idx = open_new_layer();
431 /* Link this context to the new layer */
432 new_ctx->linked_layer_idx = new_layer_idx;
433 /* New layer's parent is current layer */
434 link_layer(new_layer_idx, parent_layer_idx);
435
436 } else {
437 /* Parent comp's layer is not yet finalised, link
438 * new component to the same layer as parent
439 */
440 new_ctx->linked_layer_idx = parent_layer_idx;
441 }
442}
443
444dpe_error_t derive_child_request(int input_ctx_handle,
445 bool retain_parent_context,
446 bool allow_child_to_derive,
447 bool create_certificate,
448 const DiceInputValues *dice_inputs,
449 int32_t client_id,
450 int *new_child_ctx_handle,
451 int *new_parent_ctx_handle)
452{
Maulik Patel58595d32023-06-22 10:08:53 +0100453 dpe_error_t err;
Maulik Patelad2f3db2023-05-17 15:41:36 +0100454 struct component_context_t *child_ctx, *parent_ctx, *new_ctx;
455 uint16_t input_child_idx, input_parent_idx;
456
457#ifdef TFM_S_REG_TEST
Maulik Patel58595d32023-06-22 10:08:53 +0100458 //TODO: Remove this TEST_ROT_CDI_VAL CDI once actual CDI is calculated by BL1_1
459 psa_status_t status;
460 uint8_t dpe_rot_cdi[DICE_CDI_SIZE] = TEST_ROT_CDI_VAL;
461
Maulik Patelad2f3db2023-05-17 15:41:36 +0100462 if (layer_ctx_array[DPE_ROT_LAYER_IDX].state != LAYER_STATE_FINALISED) {
Maulik Patel58595d32023-06-22 10:08:53 +0100463
464 status = create_layer_cdi_key(&layer_ctx_array[DPE_ROT_LAYER_IDX],
465 &dpe_rot_cdi[0],
466 sizeof(dpe_rot_cdi));
467 if (status != PSA_SUCCESS) {
468 return status;
469 }
470
Maulik Patelad2f3db2023-05-17 15:41:36 +0100471 return derive_rot_context(dice_inputs,
472 new_child_ctx_handle,
473 new_parent_ctx_handle);
474 }
475#endif /* TFM_S_REG_TEST */
476
477 log_derive_child(input_ctx_handle, retain_parent_context,
478 allow_child_to_derive, create_certificate, dice_inputs,
479 client_id);
480
481 /* Validate dice inputs */
482 if (!is_dice_input_valid(dice_inputs)) {
483 return DPE_INVALID_ARGUMENT;
484 }
485
486 /* Validate input handle */
487 if (!is_input_handle_valid(input_ctx_handle)) {
488 return DPE_INVALID_ARGUMENT;
489 }
490 /* Get child component index from the input handle */
491 input_child_idx = GET_IDX(input_ctx_handle);
492 /* Get parent index of input referenced child component */
493 input_parent_idx = component_ctx_array[input_child_idx].parent_idx;
494
495 /* Below check is for safety only; It should not happen
496 * input_child_idx is already checked above in is_input_handle_valid()
497 */
498 assert(input_parent_idx < MAX_NUM_OF_COMPONENTS);
499
500 child_ctx = &component_ctx_array[input_child_idx];
501 parent_ctx = &component_ctx_array[input_parent_idx];
502
503 //TODO: Question: how to get mhu id of incoming request?
504 if (!is_input_client_id_valid(client_id)) {
505 return DPE_INVALID_ARGUMENT;
506 }
507
508 /* Copy dice input to the child component context */
Maulik Patel58595d32023-06-22 10:08:53 +0100509 err = copy_dice_input(child_ctx, dice_inputs);
510 if (err != DPE_NO_ERROR) {
511 return err;
Maulik Patelad2f3db2023-05-17 15:41:36 +0100512 }
513
514 if (create_certificate) {
Maulik Patel58595d32023-06-22 10:08:53 +0100515 err = derive_child_create_certificate(child_ctx->linked_layer_idx);
516 if (err != DPE_NO_ERROR) {
517 return err;
Maulik Patelad2f3db2023-05-17 15:41:36 +0100518 }
519 }
520
521 if (allow_child_to_derive) {
522 /* Generate new handle for child for subsequent requests */
523 if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
524 return DPE_INTERNAL_ERROR;
525 }
526 /* Update the component context array element as pointed by newly generated handle */
527 new_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
528 /* Update nonce in new child component context */
529 new_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
530 /* Update parent idx in new child component context */
531 new_ctx->parent_idx = input_child_idx;
532 /* Mark new child component index as in use */
533 new_ctx->in_use = true;
534 assign_layer_to_context(new_ctx);
535
536 } else {
537 /* Child not deriving any children */
538 /* Tag this component as a leaf */
539 child_ctx->is_leaf = true;
540 invalidate_handle(new_child_ctx_handle);
541 /* Renew nonce of child context so it cannot be used again */
542 child_ctx->nonce = INVALID_NONCE_VALUE;
543 }
544
545 if (retain_parent_context) {
546 /* Parent deriving multiple children */
547 /* Generate new handle for child for the same parent for subsequent requests */
548 if (generate_new_handle(new_parent_ctx_handle) != DPE_NO_ERROR) {
549 return DPE_INTERNAL_ERROR;
550 }
551 /* Update the component context array element as pointed by newly generated handle */
552 new_ctx = &component_ctx_array[GET_IDX(*new_parent_ctx_handle)];
553 /* Update nonce in new child component context */
554 new_ctx->nonce = GET_NONCE(*new_parent_ctx_handle);
555 /* Update parent idx in new child component context */
556 new_ctx->parent_idx = input_parent_idx;
557 /* Mark new child component index as in use */
558 new_ctx->in_use = true;
559 assign_layer_to_context(new_ctx);
560
561 } else {
562 /* Parent not deriving any more children */
563 /* No need to return parent handle */
564 invalidate_handle(new_parent_ctx_handle);
565 /* Renew nonce of parent context so it cannot be used again */
566 parent_ctx->nonce = INVALID_NONCE_VALUE;
567 }
568
569 return DPE_NO_ERROR;
570}
Maulik Patel54d65f72023-06-28 13:04:36 +0100571
572dpe_error_t destroy_context_request(int input_ctx_handle,
573 bool destroy_recursively)
574{
575 uint16_t input_ctx_idx, linked_layer_idx;
576 int i;
577 bool is_layer_empty;
578
579 log_destroy_context(input_ctx_handle, destroy_recursively);
580
581 /* Get child component index and linked layer from the input handle */
582 input_ctx_idx = GET_IDX(input_ctx_handle);
583
584#ifdef TFM_S_REG_TEST
585 if (input_ctx_idx == 0) {
586 invalidate_layer(DPE_ROT_LAYER_IDX);
587 set_context_to_default(0);
588 return DPE_NO_ERROR;
589 }
590#endif /* TFM_S_REG_TEST */
591
592 /* Validate input handle */
593 if (!is_input_handle_valid(input_ctx_handle)) {
594 return DPE_INVALID_ARGUMENT;
595 }
596 linked_layer_idx = component_ctx_array[input_ctx_idx].linked_layer_idx;
597
598#ifndef TFM_S_REG_TEST
599 if (linked_layer_idx <= DPE_DESTROY_CONTEXT_THRESHOLD_LAYER_IDX) {
600 /* All layers till hypervisor cannot be destroyed dynamically */
601 return DPE_INVALID_ARGUMENT;
602 }
603#endif /* !TFM_S_REG_TEST */
604
605
606 if (!destroy_recursively) {
607 set_context_to_default(input_ctx_idx);
608 } else {
609 //TODO: To be implemented
610 }
611
612 assert(linked_layer_idx < MAX_NUM_OF_LAYERS);
613
614 /* Close the layer if all of its contexts are destroyed */
615 is_layer_empty = true;
616 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
617 if (component_ctx_array[i].linked_layer_idx == linked_layer_idx) {
618 /* There are active component context in the layer */
619 is_layer_empty = false;
620 break;
621 }
622 }
623
624 if (is_layer_empty) {
625 invalidate_layer(linked_layer_idx);
626 }
627
628 return DPE_NO_ERROR;
629}