1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2023, Linaro Limited
4 */
5
6 #ifndef __KERNEL_TRANSFER_LIST_H
7 #define __KERNEL_TRANSFER_LIST_H
8
9 #define TRANSFER_LIST_SIGNATURE U(0x4a0fb10b)
10 #define TRANSFER_LIST_VERSION U(0x0001)
11
12 /*
13 * Init value of maximum alignment required by any transfer entry data in the TL
14 * specified as a power of two
15 */
16 #define TRANSFER_LIST_INIT_MAX_ALIGN U(3)
17
18 /* Alignment required by transfer entry header start address, in bytes */
19 #define TRANSFER_LIST_GRANULE U(8)
20
21 /*
22 * Version of the register convention used.
23 * Set to 1 for both AArch64 and AArch32 according to fw handoff spec v0.9
24 */
25 #define TL_REG_CONVENTION_VER_SHIFT_64 UL(32)
26 #define TL_REG_CONVENTION_VER_SHIFT_32 UL(24)
27 #define TL_REG_CONVENTION_VER_MASK UL(0xff)
28 #define TL_REG_CONVENTION_VER UL(1)
29
30 #define TL_HANDOFF_X1_VALUE(__version) \
31 ((TRANSFER_LIST_SIGNATURE & \
32 ((BIT64(TL_REG_CONVENTION_VER_SHIFT_64)) - 1)) | \
33 (((__version) & TL_REG_CONVENTION_VER_MASK) << \
34 TL_REG_CONVENTION_VER_SHIFT_64))
35
36 #define TL_HANDOFF_R1_VALUE(__version) \
37 ((TRANSFER_LIST_SIGNATURE & \
38 ((BIT32(TL_REG_CONVENTION_VER_SHIFT_32)) - 1)) | \
39 (((__version) & TL_REG_CONVENTION_VER_MASK) << \
40 TL_REG_CONVENTION_VER_SHIFT_32))
41
42 #define TL_FLAGS_HAS_CHECKSUM BIT(0)
43
44 /* Transfer list operation codes */
45 #define TL_OPS_NONE U(0) /* invalid for any operation */
46 #define TL_OPS_ALL U(1) /* valid for all operations */
47 #define TL_OPS_RO U(2) /* valid for read only */
48 #define TL_OPS_CUS U(3) /* either abort or special code to interpret */
49
50 #ifndef __ASSEMBLER__
51
52 #include <types_ext.h>
53
54 /* Get alignment from a value specified as power of two */
55 #define TL_ALIGNMENT_FROM_ORDER(a) BIT(a)
56
57 enum transfer_list_tag_id {
58 TL_TAG_EMPTY = 0,
59 TL_TAG_FDT = 1,
60 TL_TAG_HOB_BLOCK = 2,
61 TL_TAG_HOB_LIST = 3,
62 TL_TAG_ACPI_TABLE_AGGREGATE = 4,
63 TL_TAG_OPTEE_PAGABLE_PART = 0x100,
64 };
65
66 struct transfer_list_header {
67 uint32_t signature;
68 uint8_t checksum;
69 uint8_t version;
70 uint8_t hdr_size;
71 uint8_t alignment; /* max alignment of transfer entry data */
72 uint32_t size; /* TL header + all transfer entries */
73 uint32_t max_size;
74 uint32_t flags;
75 uint32_t reserved; /* spare bytes */
76 /*
77 * Commented out element used to visualize dynamic part of the
78 * data structure.
79 *
80 * Note that struct transfer_list_entry also is dynamic in size
81 * so the elements can't be indexed directly but instead must be
82 * traversed in order
83 *
84 * struct transfer_list_entry entries[];
85 */
86 };
87
88 struct transfer_list_entry {
89 uint16_t tag_id;
90 uint8_t reserved0; /* place holder for tag ID 3rd byte (MSB) */
91 uint8_t hdr_size;
92 uint32_t data_size;
93 /*
94 * Commented out element used to visualize dynamic part of the
95 * data structure.
96 *
97 * Note that padding is added at the end of @data to make it reach
98 * a 8-byte boundary.
99 *
100 * uint8_t data[ROUNDUP(data_size, 8)];
101 */
102 };
103
104 struct transfer_list_header *transfer_list_map(paddr_t pa);
105 void transfer_list_unmap_sync(struct transfer_list_header *tl);
106 void transfer_list_unmap_nosync(struct transfer_list_header *tl);
107
108 void transfer_list_dump(struct transfer_list_header *tl);
109 struct transfer_list_header *transfer_list_init(paddr_t pa, size_t max_size);
110
111 struct transfer_list_header *
112 transfer_list_relocate(struct transfer_list_header *tl, paddr_t pa,
113 size_t max_size);
114
115 #if defined(CFG_TRANSFER_LIST)
116
117 int transfer_list_check_header(const struct transfer_list_header *tl);
118
119 struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
120 uint16_t tag_id);
121
122 void *transfer_list_entry_data(struct transfer_list_entry *tl_e);
123
124 #else /* CFG_TRANSFER_LIST */
125
126 static inline int
transfer_list_check_header(const struct transfer_list_header * tl __unused)127 transfer_list_check_header(const struct transfer_list_header *tl __unused)
128 {
129 return TL_OPS_NONE;
130 }
131
132 static inline struct transfer_list_entry *
transfer_list_find(struct transfer_list_header * tl __unused,uint16_t tag_id __unused)133 transfer_list_find(struct transfer_list_header *tl __unused,
134 uint16_t tag_id __unused)
135 {
136 return NULL;
137 }
138
139 static inline void *
transfer_list_entry_data(struct transfer_list_entry * tl_e __unused)140 transfer_list_entry_data(struct transfer_list_entry *tl_e __unused)
141 {
142 return NULL;
143 }
144
145 #endif /* CFG_TRANSFER_LIST */
146
147 void transfer_list_update_checksum(struct transfer_list_header *tl);
148 bool transfer_list_verify_checksum(const struct transfer_list_header *tl);
149
150 bool transfer_list_set_data_size(struct transfer_list_header *tl,
151 struct transfer_list_entry *tl_e,
152 uint32_t new_data_size);
153
154 bool transfer_list_rem(struct transfer_list_header *tl,
155 struct transfer_list_entry *tl_e);
156
157 struct transfer_list_entry *transfer_list_add(struct transfer_list_header *tl,
158 uint16_t tag_id,
159 uint32_t data_size,
160 const void *data);
161
162 struct transfer_list_entry *
163 transfer_list_add_with_align(struct transfer_list_header *tl, uint16_t tag_id,
164 uint32_t data_size, const void *data,
165 uint8_t alignment);
166
167 struct transfer_list_entry *
168 transfer_list_next(struct transfer_list_header *tl,
169 struct transfer_list_entry *last);
170
171 #endif /*__ASSEMBLER__*/
172 #endif /*__TRANSFER_LIST_H*/
173