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