xref: /optee_os/core/include/kernel/transfer_list.h (revision 773d3f838f1b418257472a78e2b0425e6f439537)
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