blob: 753cb9fbe12db0fc8482ab4989fb145070c0c936 [file] [log] [blame]
Julian Hallf5728962021-06-24 09:40:23 +01001/*
2 * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdbool.h>
8#include <stdint.h>
9#include <stddef.h>
10#include "crypto_context_pool.h"
11
12static void add_to_free_list(struct crypto_context_pool *pool,
13 struct crypto_context *context);
14
15static uint32_t alloc_op_handle(struct crypto_context_pool *pool);
16static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate);
17
18
19void crypto_context_pool_init(struct crypto_context_pool *pool)
20{
21 pool->free = NULL;
22 pool->active_head = NULL;
23 pool->active_tail = NULL;
24 pool->most_recent_op_handle = 0;
25
26 for (size_t i = 0; i < CRYPTO_CONTEXT_POOL_SIZE; i++) {
27
28 add_to_free_list(pool, &pool->contexts[i]);
29 }
30}
31
32void crypto_context_pool_deinit(struct crypto_context_pool *pool)
33{
34 (void)pool;
35}
36
37struct crypto_context *crypto_context_pool_alloc(struct crypto_context_pool *pool,
38 enum crypto_context_op_id usage,
39 uint32_t client_id,
40 uint32_t *op_handle)
41{
42 struct crypto_context *context = NULL;
43
44 /* Re-cycle least-recently used context if there are no free contexts */
45 if (!pool->free && pool->active_tail) crypto_context_pool_free(pool, pool->active_tail);
46
47 /* Active context are held in a linked list in most recently allocated order */
48 if (pool->free) {
49
50 context = pool->free;
51 pool->free = context->next;
52
53 context->next = pool->active_head;
54 context->prev = NULL;
55 pool->active_head = context;
56
57 if (!pool->active_tail) pool->active_tail = context;
58 if (context->next) context->next->prev = context;
59
60 context->usage = usage;
61 context->client_id = client_id;
62
63 context->op_handle = alloc_op_handle(pool);
64 *op_handle = context->op_handle;
65 }
66
67 return context;
68}
69
70void crypto_context_pool_free(struct crypto_context_pool *pool,
71 struct crypto_context *context)
72{
73 /* Remove from active list */
74 if (context->prev) {
75 context->prev->next = context->next;
76 }
77 else {
78 pool->active_head = context->next;
79 }
80
81 if (context->next) {
82 context->next->prev = context->prev;
83 }
84 else {
85 pool->active_tail = context->prev;
86 }
87
88 /* Add to free list */
89 add_to_free_list(pool, context);
90}
91
92struct crypto_context *crypto_context_pool_find(struct crypto_context_pool *pool,
93 enum crypto_context_op_id usage,
94 uint32_t client_id,
95 uint32_t op_handle)
96{
97 /* Finds an active context that looks as though it legitimately belongs to the
98 * requesting client. Defends against bad behaviour from the client such
99 * as misusing a context for a different operation from the one that was
100 * setup.
101 */
102 struct crypto_context *found = NULL;
103 struct crypto_context *context = pool->active_head;
104
105 while (context) {
106
107 if ((context->op_handle == op_handle) &&
108 (context->usage == usage) &&
109 (context->client_id == client_id)) {
110
111 found = context;
112 break;
113 }
114
115 context = context->next;
116 }
117
118 return found;
119}
120
121static void add_to_free_list(struct crypto_context_pool *pool,
122 struct crypto_context *context)
123{
124 context->usage = CRYPTO_CONTEXT_OP_ID_NONE;
125 context->op_handle = 0;
126 context->next = pool->free;
127 context->prev = NULL;
128 pool->free = context;
129}
130
131static uint32_t alloc_op_handle(struct crypto_context_pool *pool)
132{
133 /* op handles need to be unique and to minimize the probability
134 * of a client using a stale handle that collides with a legitmately
135 * active one, use a rolling 32-bit integer.
136 */
137 uint32_t candidate = pool->most_recent_op_handle + 1;
138
139 while (op_handle_in_use(pool, candidate)) ++candidate;
140
141 pool->most_recent_op_handle = candidate;
142
143 return candidate;
144}
145
146static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate)
147{
148 bool in_use = false;
149 struct crypto_context *context = pool->active_head;
150
151 while (context && !in_use) {
152
153 in_use = (candidate == context->op_handle);
154 context = context->next;
155 }
156
157 return in_use;
158}