Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 Intel Corporation |
| 3 | * |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
| 5 | */ |
| 6 | |
Anas Nashif | bd70f6f | 2019-06-25 15:54:01 -0400 | [diff] [blame] | 7 | #include <drivers/spi.h> |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 8 | #include <syscall_handler.h> |
Andrew Boie | 375e8d7 | 2018-05-17 12:05:24 -0700 | [diff] [blame] | 9 | #include <string.h> |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 10 | |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 11 | /* This assumes that bufs and buf_copy are copies from the values passed |
| 12 | * as syscall arguments. |
| 13 | */ |
Wentong Wu | b82e202 | 2019-11-21 00:46:34 +0800 | [diff] [blame] | 14 | static struct spi_buf_set *copy_and_check(struct spi_buf_set *bufs, |
| 15 | struct spi_buf *buf_copy, |
| 16 | int writable) |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 17 | { |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 18 | size_t i; |
| 19 | |
| 20 | if (bufs->count == 0) { |
| 21 | bufs->buffers = NULL; |
Wentong Wu | b82e202 | 2019-11-21 00:46:34 +0800 | [diff] [blame] | 22 | return NULL; |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 23 | } |
| 24 | |
| 25 | /* Validate the array of struct spi_buf instances */ |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 26 | Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(bufs->buffers, |
| 27 | bufs->count, |
Andrew Boie | 375e8d7 | 2018-05-17 12:05:24 -0700 | [diff] [blame] | 28 | sizeof(struct spi_buf))); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 29 | |
Wentong Wu | aa37522 | 2019-11-21 00:47:55 +0800 | [diff] [blame] | 30 | /* Not worried about overflow here: _SYSCALL_MEMORY_ARRAY_READ() |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 31 | * 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 Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 38 | /* Now for each array element, validate the memory buffers |
| 39 | * that they point to |
| 40 | */ |
Andrew Boie | 375e8d7 | 2018-05-17 12:05:24 -0700 | [diff] [blame] | 41 | const struct spi_buf *buf = &bufs->buffers[i]; |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 42 | |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 43 | Z_OOPS(Z_SYSCALL_MEMORY(buf->buf, buf->len, writable)); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 44 | } |
Wentong Wu | b82e202 | 2019-11-21 00:46:34 +0800 | [diff] [blame] | 45 | |
| 46 | return bufs; |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 47 | } |
| 48 | |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 49 | /* 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 Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 55 | static 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 Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 59 | { |
| 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 Wu | b82e202 | 2019-11-21 00:46:34 +0800 | [diff] [blame] | 63 | tx_bufs = copy_and_check(tx_bufs, tx_buf_copy, 0); |
| 64 | rx_bufs = copy_and_check(rx_bufs, rx_buf_copy, 1); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 65 | |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 66 | return z_impl_spi_transceive((const struct device *)dev, config, |
| 67 | tx_bufs, rx_bufs); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 68 | } |
| 69 | |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 70 | static 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 Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 74 | { |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 75 | struct spi_buf_set tx_bufs_copy; |
| 76 | struct spi_buf_set rx_bufs_copy; |
| 77 | struct spi_config config_copy; |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 78 | |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 79 | Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config))); |
| 80 | Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, transceive)); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 81 | |
Tomasz Bursztyka | ea2431f | 2018-01-30 13:49:01 +0100 | [diff] [blame] | 82 | if (tx_bufs) { |
| 83 | const struct spi_buf_set *tx = |
| 84 | (const struct spi_buf_set *)tx_bufs; |
| 85 | |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 86 | Z_OOPS(Z_SYSCALL_MEMORY_READ(tx_bufs, |
| 87 | sizeof(struct spi_buf_set))); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 88 | memcpy(&tx_bufs_copy, tx, sizeof(tx_bufs_copy)); |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 89 | Z_OOPS(Z_SYSCALL_VERIFY(tx_bufs_copy.count < 32)); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 90 | } else { |
| 91 | memset(&tx_bufs_copy, 0, sizeof(tx_bufs_copy)); |
Tomasz Bursztyka | ea2431f | 2018-01-30 13:49:01 +0100 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | if (rx_bufs) { |
| 95 | const struct spi_buf_set *rx = |
| 96 | (const struct spi_buf_set *)rx_bufs; |
| 97 | |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 98 | Z_OOPS(Z_SYSCALL_MEMORY_READ(rx_bufs, |
| 99 | sizeof(struct spi_buf_set))); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 100 | memcpy(&rx_bufs_copy, rx, sizeof(rx_bufs_copy)); |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 101 | Z_OOPS(Z_SYSCALL_VERIFY(rx_bufs_copy.count < 32)); |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 102 | } else { |
| 103 | memset(&rx_bufs_copy, 0, sizeof(rx_bufs_copy)); |
Tomasz Bursztyka | ea2431f | 2018-01-30 13:49:01 +0100 | [diff] [blame] | 104 | } |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 105 | |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 106 | memcpy(&config_copy, config, sizeof(*config)); |
| 107 | if (config_copy.cs) { |
| 108 | const struct spi_cs_control *cs = config_copy.cs; |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 109 | |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 110 | Z_OOPS(Z_SYSCALL_MEMORY_READ(cs, sizeof(*cs))); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 111 | if (cs->gpio_dev) { |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 112 | Z_OOPS(Z_SYSCALL_OBJ(cs->gpio_dev, K_OBJ_DRIVER_GPIO)); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 116 | return copy_bufs_and_transceive((const struct device *)dev, |
Leandro Pereira | 845ac3e | 2018-05-14 13:27:06 -0700 | [diff] [blame] | 117 | &config_copy, |
| 118 | &tx_bufs_copy, |
Andy Ross | 075c94f | 2019-08-13 11:34:34 -0700 | [diff] [blame] | 119 | &rx_bufs_copy); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 120 | } |
Andy Ross | 075c94f | 2019-08-13 11:34:34 -0700 | [diff] [blame] | 121 | #include <syscalls/spi_transceive_mrsh.c> |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 122 | |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 123 | static inline int z_vrfy_spi_release(const struct device *dev, |
| 124 | const struct spi_config *config) |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 125 | { |
Andrew Boie | 8345e5e | 2018-05-04 15:57:57 -0700 | [diff] [blame] | 126 | Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config))); |
| 127 | Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, release)); |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 128 | return z_impl_spi_release((const struct device *)dev, config); |
Andrew Boie | 0cb0447 | 2017-10-26 14:21:35 -0700 | [diff] [blame] | 129 | } |
Andy Ross | 075c94f | 2019-08-13 11:34:34 -0700 | [diff] [blame] | 130 | #include <syscalls/spi_release_mrsh.c> |