blob: bd7365f3874d59dbb7911370d073e6fc43893499 [file] [log] [blame]
Julian Halle35efa52022-10-31 16:34:58 +00001/*
2 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Julian Halle35efa52022-10-31 16:34:58 +00007#include "stream_manager.h"
8
Gyorgy Szing3c446242023-03-31 01:53:15 +02009#include <stddef.h>
10#include <string.h>
11
Imre Kis7554c472024-07-04 10:09:31 +020012#include "protocols/service/fwu/status.h"
Gyorgy Szing3c446242023-03-31 01:53:15 +020013#include "service/fwu/fw_store/fw_store.h"
14
15static uint32_t generate_handle(struct stream_manager *subject,
16 const struct stream_context *const context)
Julian Halle35efa52022-10-31 16:34:58 +000017{
18 /* Handle includes rolling count value to protect against use of a stale handle */
19 uint32_t new_handle = context - subject->contexts;
20
21 new_handle = (new_handle & 0xffff) | (subject->rolling_count << 16);
22 ++subject->rolling_count;
23 return new_handle;
24}
25
26static uint32_t index_from_handle(uint32_t handle)
27{
28 return handle & 0xffff;
29}
30
Gyorgy Szing3c446242023-03-31 01:53:15 +020031static void add_to_free_list(struct stream_manager *subject, struct stream_context *context)
Julian Halle35efa52022-10-31 16:34:58 +000032{
33 context->type = FWU_STREAM_TYPE_NONE;
34 context->handle = 0;
35 context->next = subject->free;
36 context->prev = NULL;
37 subject->free = context;
38}
39
Gyorgy Szing3c446242023-03-31 01:53:15 +020040static struct stream_context *alloc_stream_context(struct stream_manager *subject,
41 enum fwu_stream_type type, uint32_t *handle)
Julian Halle35efa52022-10-31 16:34:58 +000042{
43 struct stream_context *context = NULL;
44
45 /* Re-cycle least-recently used context if there are no free contexts */
46 if (!subject->free && subject->active_tail) {
Gyorgy Szing3c446242023-03-31 01:53:15 +020047 stream_manager_close(subject, subject->active_tail->handle, false);
Julian Halle35efa52022-10-31 16:34:58 +000048 }
49
50 /* Active contexts are held in a linked list in most recently allocated order */
51 if (subject->free) {
Julian Halle35efa52022-10-31 16:34:58 +000052 context = subject->free;
53 subject->free = context->next;
54
55 context->next = subject->active_head;
56 context->prev = NULL;
57 subject->active_head = context;
58
59 if (!subject->active_tail)
60 subject->active_tail = context;
61
62 if (context->next)
63 context->next->prev = context;
64
65 context->type = type;
66
67 context->handle = generate_handle(subject, context);
68 *handle = context->handle;
69 }
70
71 return context;
72}
73
Gyorgy Szing3c446242023-03-31 01:53:15 +020074static void free_stream_context(struct stream_manager *subject, struct stream_context *context)
Julian Halle35efa52022-10-31 16:34:58 +000075{
76 /* Remove from active list */
77 if (context->prev)
78 context->prev->next = context->next;
79 else
80 subject->active_head = context->next;
81
82 if (context->next)
83 context->next->prev = context->prev;
84 else
85 subject->active_tail = context->prev;
86
87 /* Add to free list */
88 add_to_free_list(subject, context);
89}
90
Gyorgy Szing3c446242023-03-31 01:53:15 +020091static struct stream_context *get_active_context(struct stream_manager *subject, uint32_t handle)
Julian Halle35efa52022-10-31 16:34:58 +000092{
93 struct stream_context *context = NULL;
94 uint32_t index = index_from_handle(handle);
95
96 if ((index < FWU_STREAM_MANAGER_POOL_SIZE) &&
Gyorgy Szing3c446242023-03-31 01:53:15 +020097 (subject->contexts[index].type != FWU_STREAM_TYPE_NONE) &&
98 (subject->contexts[index].handle == handle)) {
Julian Halle35efa52022-10-31 16:34:58 +000099 /* Handle qualifies an active stream context */
100 context = &subject->contexts[index];
101 }
102
103 return context;
104}
105
Gyorgy Szing3c446242023-03-31 01:53:15 +0200106void stream_manager_init(struct stream_manager *subject)
Julian Halle35efa52022-10-31 16:34:58 +0000107{
108 subject->free = NULL;
109 subject->active_head = NULL;
110 subject->active_tail = NULL;
111 subject->rolling_count = 0;
112
113 for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++)
114 add_to_free_list(subject, &subject->contexts[i]);
115}
116
Gyorgy Szing3c446242023-03-31 01:53:15 +0200117void stream_manager_deinit(struct stream_manager *subject)
Julian Halle35efa52022-10-31 16:34:58 +0000118{
119 (void)subject;
120}
121
Gyorgy Szing3c446242023-03-31 01:53:15 +0200122int stream_manager_open_buffer_stream(struct stream_manager *subject, const uint8_t *data,
123 size_t data_len, uint32_t *handle)
Julian Halle35efa52022-10-31 16:34:58 +0000124{
125 struct stream_context *context;
126 int status = FWU_STATUS_UNKNOWN;
127
128 /* First cancel any buffer streams left open associated with
129 * the same source buffer. Concurrent stream access to data in
130 * a buffer is prevented to avoid the possibility of a buffer
131 * being updated while a read stream is open.
132 */
133 for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
Julian Halle35efa52022-10-31 16:34:58 +0000134 context = &subject->contexts[i];
135
136 if ((context->type == FWU_STREAM_TYPE_BUFFER) &&
Gyorgy Szing3c446242023-03-31 01:53:15 +0200137 (context->variant.buffer.data == data))
Julian Halle35efa52022-10-31 16:34:58 +0000138 free_stream_context(subject, context);
139 }
140
141 /* Allocate and initialize a new stream */
Gyorgy Szing3c446242023-03-31 01:53:15 +0200142 context = alloc_stream_context(subject, FWU_STREAM_TYPE_BUFFER, handle);
Julian Halle35efa52022-10-31 16:34:58 +0000143
144 if (context) {
Julian Halle35efa52022-10-31 16:34:58 +0000145 context->variant.buffer.data = data;
146 context->variant.buffer.data_len = data_len;
147 context->variant.buffer.pos = 0;
148
149 status = FWU_STATUS_SUCCESS;
150 }
151
152 return status;
153}
154
Gyorgy Szing3c446242023-03-31 01:53:15 +0200155int stream_manager_open_install_stream(struct stream_manager *subject, struct fw_store *fw_store,
156 struct installer *installer,
157 const struct image_info *image_info, uint32_t *stream_handle)
Julian Halle35efa52022-10-31 16:34:58 +0000158{
159 struct stream_context *context;
160 int status = FWU_STATUS_UNKNOWN;
161
162 /* First cancel any install streams left open associated with
163 * the same fw_store and installer. This defends against the
164 * possibility of data written via two streams being written to the
165 * same installer, resulting in image corruption.
166 */
167 for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
Julian Halle35efa52022-10-31 16:34:58 +0000168 context = &subject->contexts[i];
169
170 if ((context->type == FWU_STREAM_TYPE_INSTALL) &&
Gyorgy Szing3c446242023-03-31 01:53:15 +0200171 (context->variant.install.fw_store == fw_store) &&
172 (context->variant.install.installer == installer))
Julian Halle35efa52022-10-31 16:34:58 +0000173 free_stream_context(subject, context);
174 }
175
176 /* Allocate and initialize a new stream */
Gyorgy Szing3c446242023-03-31 01:53:15 +0200177 context = alloc_stream_context(subject, FWU_STREAM_TYPE_INSTALL, stream_handle);
Julian Halle35efa52022-10-31 16:34:58 +0000178
179 if (context) {
Julian Halle35efa52022-10-31 16:34:58 +0000180 context->variant.install.fw_store = fw_store;
181 context->variant.install.installer = installer;
182 context->variant.install.image_info = image_info;
183
184 status = FWU_STATUS_SUCCESS;
185 }
186
187 return status;
188}
189
Gyorgy Szing3c446242023-03-31 01:53:15 +0200190int stream_manager_close(struct stream_manager *subject, uint32_t handle, bool accepted)
Julian Halle35efa52022-10-31 16:34:58 +0000191{
192 int status = FWU_STATUS_UNKNOWN;
193 struct stream_context *context = get_active_context(subject, handle);
194
195 if (context) {
Julian Halle35efa52022-10-31 16:34:58 +0000196 status = FWU_STATUS_SUCCESS;
197
198 if (context->type == FWU_STREAM_TYPE_INSTALL) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200199 status = fw_store_commit_image(context->variant.install.fw_store,
200 context->variant.install.installer,
201 context->variant.install.image_info,
202 accepted);
Julian Halle35efa52022-10-31 16:34:58 +0000203 }
204
205 free_stream_context(subject, context);
206 }
207
208 return status;
209}
210
Gyorgy Szing3c446242023-03-31 01:53:15 +0200211void stream_manager_cancel_streams(struct stream_manager *subject, enum fwu_stream_type type)
Julian Halle35efa52022-10-31 16:34:58 +0000212{
213 for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
Julian Halle35efa52022-10-31 16:34:58 +0000214 struct stream_context *context = &subject->contexts[i];
215
216 if (context->type == type)
217 free_stream_context(subject, context);
218 }
219}
220
Gyorgy Szing3c446242023-03-31 01:53:15 +0200221bool stream_manager_is_open_streams(const struct stream_manager *subject, enum fwu_stream_type type)
Julian Halle35efa52022-10-31 16:34:58 +0000222{
223 bool any_open = false;
224
225 for (size_t i = 0; i < FWU_STREAM_MANAGER_POOL_SIZE; i++) {
Julian Halle35efa52022-10-31 16:34:58 +0000226 const struct stream_context *context = &subject->contexts[i];
227
228 if (context->type == type) {
Julian Halle35efa52022-10-31 16:34:58 +0000229 any_open = true;
230 break;
231 }
232 }
233
234 return any_open;
235}
236
Gyorgy Szing3c446242023-03-31 01:53:15 +0200237int stream_manager_write(struct stream_manager *subject, uint32_t handle, const uint8_t *data,
238 size_t data_len)
Julian Halle35efa52022-10-31 16:34:58 +0000239{
240 int status = FWU_STATUS_UNKNOWN;
241 struct stream_context *context = get_active_context(subject, handle);
242
243 if (context && context->type == FWU_STREAM_TYPE_INSTALL) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200244 status = fw_store_write_image(context->variant.install.fw_store,
245 context->variant.install.installer, data, data_len);
Julian Halle35efa52022-10-31 16:34:58 +0000246 }
247
248 return status;
249}
250
Gyorgy Szing3c446242023-03-31 01:53:15 +0200251int stream_manager_read(struct stream_manager *subject, uint32_t handle, uint8_t *buf,
252 size_t buf_size, size_t *read_len, size_t *total_len)
Julian Halle35efa52022-10-31 16:34:58 +0000253{
254 int status = FWU_STATUS_UNKNOWN;
255 struct stream_context *context = get_active_context(subject, handle);
256
257 if (context) {
Julian Halle35efa52022-10-31 16:34:58 +0000258 if (context->type == FWU_STREAM_TYPE_BUFFER) {
Julian Halle35efa52022-10-31 16:34:58 +0000259 size_t pos = context->variant.buffer.pos;
260 size_t remaining_len = context->variant.buffer.data_len - pos;
Gyorgy Szing3c446242023-03-31 01:53:15 +0200261 size_t len_to_read = (remaining_len <= buf_size) ? remaining_len : buf_size;
Julian Halle35efa52022-10-31 16:34:58 +0000262
263 memcpy(buf, &context->variant.buffer.data[pos], len_to_read);
264
265 *read_len = len_to_read;
266 *total_len = context->variant.buffer.data_len;
267 context->variant.buffer.pos = pos + len_to_read;
268
269 status = FWU_STATUS_SUCCESS;
270 } else {
Julian Halle35efa52022-10-31 16:34:58 +0000271 /* Reading from other types of stream is forbidden */
272 status = FWU_STATUS_DENIED;
273 }
274 }
275
276 return status;
277}