blob: e44f02988dade5f9236fcd2b1b3fd00efd0c4767 [file] [log] [blame]
Andrew Boie0cb04472017-10-26 14:21:35 -07001/*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
Anas Nashifbd70f6f2019-06-25 15:54:01 -04007#include <drivers/spi.h>
Andrew Boie0cb04472017-10-26 14:21:35 -07008#include <syscall_handler.h>
Andrew Boie375e8d72018-05-17 12:05:24 -07009#include <string.h>
Andrew Boie0cb04472017-10-26 14:21:35 -070010
Leandro Pereira845ac3e2018-05-14 13:27:06 -070011/* This assumes that bufs and buf_copy are copies from the values passed
12 * as syscall arguments.
13 */
Wentong Wub82e2022019-11-21 00:46:34 +080014static struct spi_buf_set *copy_and_check(struct spi_buf_set *bufs,
15 struct spi_buf *buf_copy,
16 int writable)
Andrew Boie0cb04472017-10-26 14:21:35 -070017{
Leandro Pereira845ac3e2018-05-14 13:27:06 -070018 size_t i;
19
20 if (bufs->count == 0) {
21 bufs->buffers = NULL;
Wentong Wub82e2022019-11-21 00:46:34 +080022 return NULL;
Andrew Boie0cb04472017-10-26 14:21:35 -070023 }
24
25 /* Validate the array of struct spi_buf instances */
Andrew Boie8345e5e2018-05-04 15:57:57 -070026 Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(bufs->buffers,
27 bufs->count,
Andrew Boie375e8d72018-05-17 12:05:24 -070028 sizeof(struct spi_buf)));
Andrew Boie0cb04472017-10-26 14:21:35 -070029
Wentong Wuaa375222019-11-21 00:47:55 +080030 /* Not worried about overflow here: _SYSCALL_MEMORY_ARRAY_READ()
Leandro Pereira845ac3e2018-05-14 13:27:06 -070031 * takes care of it.
32 */
33 bufs->buffers = memcpy(buf_copy,
34 bufs->buffers,
35 bufs->count * sizeof(struct spi_buf));
36
37 for (i = 0; i < bufs->count; i++) {
Andrew Boie0cb04472017-10-26 14:21:35 -070038 /* Now for each array element, validate the memory buffers
39 * that they point to
40 */
Andrew Boie375e8d72018-05-17 12:05:24 -070041 const struct spi_buf *buf = &bufs->buffers[i];
Leandro Pereira845ac3e2018-05-14 13:27:06 -070042
Andrew Boie8345e5e2018-05-04 15:57:57 -070043 Z_OOPS(Z_SYSCALL_MEMORY(buf->buf, buf->len, writable));
Andrew Boie0cb04472017-10-26 14:21:35 -070044 }
Wentong Wub82e2022019-11-21 00:46:34 +080045
46 return bufs;
Andrew Boie0cb04472017-10-26 14:21:35 -070047}
48
Leandro Pereira845ac3e2018-05-14 13:27:06 -070049/* This function is only here so tx_buf_copy and rx_buf_copy can be allocated
50 * using VLA. It assumes that both tx_bufs and rx_bufs will receive a copy of
51 * the values passed to the syscall as arguments. It also assumes that the
52 * count member has been verified and is a value that won't lead to stack
53 * overflow.
54 */
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020055static uint32_t copy_bufs_and_transceive(const struct device *dev,
56 const struct spi_config *config,
57 struct spi_buf_set *tx_bufs,
58 struct spi_buf_set *rx_bufs)
Leandro Pereira845ac3e2018-05-14 13:27:06 -070059{
60 struct spi_buf tx_buf_copy[tx_bufs->count ? tx_bufs->count : 1];
61 struct spi_buf rx_buf_copy[rx_bufs->count ? rx_bufs->count : 1];
62
Wentong Wub82e2022019-11-21 00:46:34 +080063 tx_bufs = copy_and_check(tx_bufs, tx_buf_copy, 0);
64 rx_bufs = copy_and_check(rx_bufs, rx_buf_copy, 1);
Leandro Pereira845ac3e2018-05-14 13:27:06 -070065
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020066 return z_impl_spi_transceive((const struct device *)dev, config,
67 tx_bufs, rx_bufs);
Leandro Pereira845ac3e2018-05-14 13:27:06 -070068}
69
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020070static inline int z_vrfy_spi_transceive(const struct device *dev,
71 const struct spi_config *config,
72 const struct spi_buf_set *tx_bufs,
73 const struct spi_buf_set *rx_bufs)
Andrew Boie0cb04472017-10-26 14:21:35 -070074{
Leandro Pereira845ac3e2018-05-14 13:27:06 -070075 struct spi_buf_set tx_bufs_copy;
76 struct spi_buf_set rx_bufs_copy;
77 struct spi_config config_copy;
Andrew Boie0cb04472017-10-26 14:21:35 -070078
Andrew Boie8345e5e2018-05-04 15:57:57 -070079 Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config)));
80 Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, transceive));
Andrew Boie0cb04472017-10-26 14:21:35 -070081
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +010082 if (tx_bufs) {
83 const struct spi_buf_set *tx =
84 (const struct spi_buf_set *)tx_bufs;
85
Andrew Boie8345e5e2018-05-04 15:57:57 -070086 Z_OOPS(Z_SYSCALL_MEMORY_READ(tx_bufs,
87 sizeof(struct spi_buf_set)));
Leandro Pereira845ac3e2018-05-14 13:27:06 -070088 memcpy(&tx_bufs_copy, tx, sizeof(tx_bufs_copy));
Andrew Boie8345e5e2018-05-04 15:57:57 -070089 Z_OOPS(Z_SYSCALL_VERIFY(tx_bufs_copy.count < 32));
Leandro Pereira845ac3e2018-05-14 13:27:06 -070090 } else {
91 memset(&tx_bufs_copy, 0, sizeof(tx_bufs_copy));
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +010092 }
93
94 if (rx_bufs) {
95 const struct spi_buf_set *rx =
96 (const struct spi_buf_set *)rx_bufs;
97
Andrew Boie8345e5e2018-05-04 15:57:57 -070098 Z_OOPS(Z_SYSCALL_MEMORY_READ(rx_bufs,
99 sizeof(struct spi_buf_set)));
Leandro Pereira845ac3e2018-05-14 13:27:06 -0700100 memcpy(&rx_bufs_copy, rx, sizeof(rx_bufs_copy));
Andrew Boie8345e5e2018-05-04 15:57:57 -0700101 Z_OOPS(Z_SYSCALL_VERIFY(rx_bufs_copy.count < 32));
Leandro Pereira845ac3e2018-05-14 13:27:06 -0700102 } else {
103 memset(&rx_bufs_copy, 0, sizeof(rx_bufs_copy));
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +0100104 }
Andrew Boie0cb04472017-10-26 14:21:35 -0700105
Leandro Pereira845ac3e2018-05-14 13:27:06 -0700106 memcpy(&config_copy, config, sizeof(*config));
107 if (config_copy.cs) {
108 const struct spi_cs_control *cs = config_copy.cs;
Andrew Boie0cb04472017-10-26 14:21:35 -0700109
Andrew Boie8345e5e2018-05-04 15:57:57 -0700110 Z_OOPS(Z_SYSCALL_MEMORY_READ(cs, sizeof(*cs)));
Andrew Boie0cb04472017-10-26 14:21:35 -0700111 if (cs->gpio_dev) {
Andrew Boie8345e5e2018-05-04 15:57:57 -0700112 Z_OOPS(Z_SYSCALL_OBJ(cs->gpio_dev, K_OBJ_DRIVER_GPIO));
Andrew Boie0cb04472017-10-26 14:21:35 -0700113 }
114 }
115
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200116 return copy_bufs_and_transceive((const struct device *)dev,
Leandro Pereira845ac3e2018-05-14 13:27:06 -0700117 &config_copy,
118 &tx_bufs_copy,
Andy Ross075c94f2019-08-13 11:34:34 -0700119 &rx_bufs_copy);
Andrew Boie0cb04472017-10-26 14:21:35 -0700120}
Andy Ross075c94f2019-08-13 11:34:34 -0700121#include <syscalls/spi_transceive_mrsh.c>
Andrew Boie0cb04472017-10-26 14:21:35 -0700122
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200123static inline int z_vrfy_spi_release(const struct device *dev,
124 const struct spi_config *config)
Andrew Boie0cb04472017-10-26 14:21:35 -0700125{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700126 Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config)));
127 Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, release));
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200128 return z_impl_spi_release((const struct device *)dev, config);
Andrew Boie0cb04472017-10-26 14:21:35 -0700129}
Andy Ross075c94f2019-08-13 11:34:34 -0700130#include <syscalls/spi_release_mrsh.c>