Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <drivers/spi.h>
#include <syscall_handler.h>
#include <string.h>
/* This assumes that bufs and buf_copy are copies from the values passed
* as syscall arguments.
*/
static struct spi_buf_set *copy_and_check(struct spi_buf_set *bufs,
struct spi_buf *buf_copy,
int writable)
{
size_t i;
if (bufs->count == 0) {
bufs->buffers = NULL;
return NULL;
}
/* Validate the array of struct spi_buf instances */
Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(bufs->buffers,
bufs->count,
sizeof(struct spi_buf)));
/* Not worried about overflow here: _SYSCALL_MEMORY_ARRAY_READ()
* takes care of it.
*/
bufs->buffers = memcpy(buf_copy,
bufs->buffers,
bufs->count * sizeof(struct spi_buf));
for (i = 0; i < bufs->count; i++) {
/* Now for each array element, validate the memory buffers
* that they point to
*/
const struct spi_buf *buf = &bufs->buffers[i];
Z_OOPS(Z_SYSCALL_MEMORY(buf->buf, buf->len, writable));
}
return bufs;
}
/* This function is only here so tx_buf_copy and rx_buf_copy can be allocated
* using VLA. It assumes that both tx_bufs and rx_bufs will receive a copy of
* the values passed to the syscall as arguments. It also assumes that the
* count member has been verified and is a value that won't lead to stack
* overflow.
*/
static u32_t copy_bufs_and_transceive(struct device *dev,
const struct spi_config *config,
struct spi_buf_set *tx_bufs,
struct spi_buf_set *rx_bufs)
{
struct spi_buf tx_buf_copy[tx_bufs->count ? tx_bufs->count : 1];
struct spi_buf rx_buf_copy[rx_bufs->count ? rx_bufs->count : 1];
tx_bufs = copy_and_check(tx_bufs, tx_buf_copy, 0);
rx_bufs = copy_and_check(rx_bufs, rx_buf_copy, 1);
return z_impl_spi_transceive((struct device *)dev, config,
tx_bufs, rx_bufs);
}
static inline int z_vrfy_spi_transceive(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
struct spi_buf_set tx_bufs_copy;
struct spi_buf_set rx_bufs_copy;
struct spi_config config_copy;
Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config)));
Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, transceive));
if (tx_bufs) {
const struct spi_buf_set *tx =
(const struct spi_buf_set *)tx_bufs;
Z_OOPS(Z_SYSCALL_MEMORY_READ(tx_bufs,
sizeof(struct spi_buf_set)));
memcpy(&tx_bufs_copy, tx, sizeof(tx_bufs_copy));
Z_OOPS(Z_SYSCALL_VERIFY(tx_bufs_copy.count < 32));
} else {
memset(&tx_bufs_copy, 0, sizeof(tx_bufs_copy));
}
if (rx_bufs) {
const struct spi_buf_set *rx =
(const struct spi_buf_set *)rx_bufs;
Z_OOPS(Z_SYSCALL_MEMORY_READ(rx_bufs,
sizeof(struct spi_buf_set)));
memcpy(&rx_bufs_copy, rx, sizeof(rx_bufs_copy));
Z_OOPS(Z_SYSCALL_VERIFY(rx_bufs_copy.count < 32));
} else {
memset(&rx_bufs_copy, 0, sizeof(rx_bufs_copy));
}
memcpy(&config_copy, config, sizeof(*config));
if (config_copy.cs) {
const struct spi_cs_control *cs = config_copy.cs;
Z_OOPS(Z_SYSCALL_MEMORY_READ(cs, sizeof(*cs)));
if (cs->gpio_dev) {
Z_OOPS(Z_SYSCALL_OBJ(cs->gpio_dev, K_OBJ_DRIVER_GPIO));
}
}
return copy_bufs_and_transceive((struct device *)dev,
&config_copy,
&tx_bufs_copy,
&rx_bufs_copy);
}
#include <syscalls/spi_transceive_mrsh.c>
static inline int z_vrfy_spi_release(struct device *dev,
const struct spi_config *config)
{
Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config)));
Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, release));
return z_impl_spi_release((struct device *)dev, config);
}
#include <syscalls/spi_release_mrsh.c>
|