1 /*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "dma350_checker_layer.h"
9 #include "dma350_ch_drv.h"
10 #include "dma350_lib.h"
11
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stddef.h>
15
16 #include <arm_cmse.h>
17
18 /* Header for target specific SCB register definitions */
19 #ifndef CMSIS_device_header
20 /* CMSIS pack default header, containing the CMSIS_device_header definition */
21 #include "RTE_Components.h"
22 #endif
23 #include CMSIS_device_header
24
25 __STATIC_INLINE
dma350_check_src_unpriv_access(const void * src,uint32_t size)26 enum dma350_lib_error_t dma350_check_src_unpriv_access(const void* src, uint32_t size)
27 {
28 if(NULL == cmse_check_address_range((void*)src, size, CMSE_MPU_UNPRIV | CMSE_MPU_READ)) {
29 return DMA350_LIB_ERR_RANGE_NOT_ACCESSIBLE;
30 }
31 return DMA350_LIB_ERR_NONE;
32 }
33
34 __STATIC_INLINE
dma350_check_dst_unpriv_access(const void * dst,uint32_t size)35 enum dma350_lib_error_t dma350_check_dst_unpriv_access(const void* dst, uint32_t size)
36 {
37 if(NULL == cmse_check_address_range((void*)dst, size, CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE)) {
38 return DMA350_LIB_ERR_RANGE_NOT_ACCESSIBLE;
39 }
40 return DMA350_LIB_ERR_NONE;
41 }
42
dma350_check_src_dst_unpriv_access(const void * src,const void * dst,uint32_t size)43 static enum dma350_lib_error_t dma350_check_src_dst_unpriv_access(const void* src, const void* dst, uint32_t size)
44 {
45 enum dma350_lib_error_t lib_error;
46 lib_error = dma350_check_src_unpriv_access(src, size);
47 if(lib_error != DMA350_LIB_ERR_NONE) {
48 return lib_error;
49 }
50 lib_error = dma350_check_dst_unpriv_access(dst, size);
51 if(lib_error != DMA350_LIB_ERR_NONE) {
52 return lib_error;
53 }
54 return DMA350_LIB_ERR_NONE;
55 }
56
dma350_get_channel(uint8_t channel,struct dma350_ch_dev_t ** ch_dev)57 static enum dma350_lib_error_t dma350_get_channel(uint8_t channel, struct dma350_ch_dev_t** ch_dev)
58 {
59 if(channel >= DMA350_CHECKER_CHANNELS.number_of_channels) {
60 return DMA350_LIB_ERR_CHANNEL_INVALID;
61 }
62 *ch_dev = DMA350_CHECKER_CHANNELS.channels[channel];
63 if(!*ch_dev) {
64 return DMA350_LIB_ERR_DEVICE_INVALID;
65 }
66 return DMA350_LIB_ERR_NONE;
67 }
68
dma350_check_channel_unpriv_access(struct dma350_ch_dev_t * ch_dev)69 static enum dma350_lib_error_t dma350_check_channel_unpriv_access(struct dma350_ch_dev_t* ch_dev)
70 {
71 if(NULL == cmse_check_address_range(ch_dev->cfg.ch_base,
72 sizeof(DMACH_TypeDef),
73 CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE)) {
74 return DMA350_LIB_ERR_RANGE_NOT_ACCESSIBLE;
75 }
76
77 return DMA350_LIB_ERR_NONE;
78 }
79
check_blocking(enum dma350_lib_exec_type_t exec_type)80 static enum dma350_lib_error_t check_blocking(enum dma350_lib_exec_type_t exec_type)
81 {
82 if((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) && (exec_type == DMA350_LIB_EXEC_BLOCKING)) {
83 /* Called from interrupt && blocking mode */
84 /* Blocking call is not allowed when using checker layer in handler mode */
85 return DMA350_LIB_ERR_CFG_ERR;
86 }
87 return DMA350_LIB_ERR_NONE;
88 }
89
dma350_call_memcpy(struct dma350_memcpy_config * config,struct dma350_ch_dev_t * ch_dev)90 static enum dma350_lib_error_t dma350_call_memcpy(struct dma350_memcpy_config *config, struct dma350_ch_dev_t* ch_dev)
91 {
92 enum dma350_lib_error_t ret_val;
93
94 ret_val = check_blocking(config->exec_type);
95 if(ret_val != DMA350_LIB_ERR_NONE) {
96 return ret_val;
97 }
98
99 ret_val = dma350_check_src_dst_unpriv_access(config->src, config->dst, config->size);
100 if(ret_val != DMA350_LIB_ERR_NONE) {
101 return ret_val;
102 }
103
104 ret_val = dma350_memcpy(ch_dev, config->src, config->dst, config->size, config->exec_type);
105
106 return ret_val;
107 }
108
dma350_call_memmove(struct dma350_memmove_config * config,struct dma350_ch_dev_t * ch_dev)109 static enum dma350_lib_error_t dma350_call_memmove(struct dma350_memmove_config *config, struct dma350_ch_dev_t* ch_dev)
110 {
111 enum dma350_lib_error_t ret_val;
112
113 ret_val = check_blocking(config->exec_type);
114 if(ret_val != DMA350_LIB_ERR_NONE) {
115 return ret_val;
116 }
117
118 ret_val = dma350_check_src_dst_unpriv_access(config->src, config->dst, config->size);
119 if(ret_val != DMA350_LIB_ERR_NONE) {
120 return ret_val;
121 }
122
123 ret_val = dma350_memmove(ch_dev, config->src, config->dst, config->size, config->exec_type);
124
125 return ret_val;
126 }
127
dma350_call_draw(struct dma350_draw_config * config,struct dma350_ch_dev_t * ch_dev)128 static enum dma350_lib_error_t dma350_call_draw(struct dma350_draw_config *config, struct dma350_ch_dev_t* ch_dev)
129 {
130 enum dma350_lib_error_t ret_val;
131 uint32_t src_size, des_size;
132
133 ret_val = check_blocking(config->exec_type);
134 if(ret_val != DMA350_LIB_ERR_NONE) {
135 return ret_val;
136 }
137
138 src_size = config->src_line_width * (config->src_height - 1) + config->src_width;
139 ret_val = dma350_check_src_unpriv_access(config->src, src_size);
140 if(ret_val != DMA350_LIB_ERR_NONE) {
141 return ret_val;
142 }
143 des_size = config->des_line_width * (config->des_height - 1) + config->des_width;;
144 ret_val = dma350_check_dst_unpriv_access(config->des, des_size);
145 if(ret_val != DMA350_LIB_ERR_NONE) {
146 return ret_val;
147 }
148
149 ret_val = dma350_draw_from_canvas(ch_dev, config->src, config->des,
150 config->src_width, config->src_height, config->src_line_width,
151 config->des_width, config->des_height, config->des_line_width,
152 config->pixelsize, config->transform, config->exec_type);
153
154 return ret_val;
155 }
156
config_dma350_for_unprivileged_actor(enum dma350_config_type_t config_type,uint8_t channel,void * config)157 enum dma350_lib_error_t config_dma350_for_unprivileged_actor(enum dma350_config_type_t config_type, uint8_t channel, void* config)
158 {
159 struct dma350_ch_dev_t* ch_dev;
160 enum dma350_lib_error_t ret_val;
161
162 ret_val = dma350_get_channel(channel, &ch_dev);
163 if(ret_val != DMA350_LIB_ERR_NONE) {
164 return ret_val;
165 }
166
167 ret_val = dma350_check_channel_unpriv_access(ch_dev);
168 if(ret_val != DMA350_LIB_ERR_NONE) {
169 return ret_val;
170 }
171
172 switch (config_type)
173 {
174 case DMA_CALL_MEMCPY:
175 ret_val = dma350_call_memcpy((struct dma350_memcpy_config *)config, ch_dev);
176 break;
177 case DMA_CALL_MEMMOVE:
178 ret_val = dma350_call_memmove((struct dma350_memmove_config *)config, ch_dev);
179 break;
180 case DMA_CALL_DRAW_FROM_CANVAS:
181 ret_val = dma350_call_draw((struct dma350_draw_config *)config, ch_dev);
182 break;
183 case DMA_CLEAR_DONE_IRQ:
184 ret_val = dma350_clear_done_irq(ch_dev);
185 break;
186 case DMA_GET_STATUS:
187 ret_val = dma350_get_status(ch_dev, (union dma350_ch_status_t *)config);
188 break;
189 default:
190 ret_val = DMA350_LIB_ERR_INVALID_CONFIG_TYPE;
191 break;
192 }
193
194 return ret_val;
195 }
196