blob: 13ff6ffe203aebf979ae9c2196344e099fe33e7c [file] [log] [blame]
Harrison Mutai6e011642023-09-22 17:17:35 +01001/*
2 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stddef.h>
8
9#include <transfer_list.h>
10
Harrison Mutai089c9ad2025-04-25 16:03:54 +000011/*******************************************************************************
12 * Search for an existing transfer entry with the specified tag id from a
13 * transfer list
14 * Return pointer to the found transfer entry or NULL on error
15 ******************************************************************************/
Harrison Mutai6e011642023-09-22 17:17:35 +010016struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
17 uint16_t tag_id)
18{
Harrison Mutai089c9ad2025-04-25 16:03:54 +000019 struct transfer_list_entry *te = NULL;
Harrison Mutai6e011642023-09-22 17:17:35 +010020
Harrison Mutai089c9ad2025-04-25 16:03:54 +000021 do {
22 te = transfer_list_next(tl, te);
23 } while (te && (te->tag_id != tag_id));
24
25 return te;
26}
27
28/*******************************************************************************
29 * Enumerate the next transfer entry
30 * Return pointer to the next transfer entry or NULL on error
31 ******************************************************************************/
32struct transfer_list_entry *transfer_list_next(struct transfer_list_header *tl,
33 struct transfer_list_entry *last)
34{
35 struct transfer_list_entry *te = NULL;
36 uintptr_t tl_ev = 0;
37 uintptr_t va = 0;
38 uintptr_t ev = 0;
39 size_t sz = 0;
40
41 if (!tl) {
42 return NULL;
43 }
44
45 tl_ev = (uintptr_t)tl + tl->size;
46
47 if (last) {
48 va = (uintptr_t)last;
49 /* check if the total size overflow */
50 if (add_overflow(last->hdr_size, last->data_size, &sz)) {
51 return NULL;
52 }
53 /* roundup to the next entry */
54 if (add_with_round_up_overflow(va, sz, TRANSFER_LIST_GRANULE,
55 &va)) {
56 return NULL;
57 }
58 } else {
59 va = (uintptr_t)tl + tl->hdr_size;
60 }
61
62 te = (struct transfer_list_entry *)va;
63
64 if (va + sizeof(*te) > tl_ev || te->hdr_size < sizeof(*te) ||
65 add_overflow(te->hdr_size, te->data_size, &sz) ||
66 add_overflow(va, sz, &ev) || ev > tl_ev) {
67 return NULL;
Harrison Mutai6e011642023-09-22 17:17:35 +010068 }
69
70 return te;
71}
72
73void *transfer_list_entry_data(struct transfer_list_entry *entry)
74{
75 return (uint8_t *)entry + entry->hdr_size;
76}
77
78/*******************************************************************************
79 * Verifying the header of a transfer list
80 * Compliant to 2.4.1 of Firmware handoff specification (v0.9)
81 * Return transfer list operation status code
82 ******************************************************************************/
83enum transfer_list_ops
84transfer_list_check_header(const struct transfer_list_header *tl)
85{
86 uint8_t byte_sum = 0U;
87 uint8_t *b = (uint8_t *)tl;
88
89 if (tl == NULL) {
90 return TL_OPS_NON;
91 }
92
93 if (tl->signature != TRANSFER_LIST_SIGNATURE ||
94 tl->size > tl->max_size) {
95 return TL_OPS_NON;
96 }
97
98 for (size_t i = 0; i < tl->size; i++) {
99 byte_sum += b[i];
100 }
101
102 if (byte_sum - tl->checksum == tl->checksum) {
103 return TL_OPS_NON;
104 }
105
106 return TL_OPS_ALL;
107}