diff options
author | Ernesto Corona <ernesto.corona@intel.com> | 2021-03-04 03:11:47 +0300 |
---|---|---|
committer | Corona, Ernesto <ernesto.corona@intel.com> | 2021-03-10 01:20:41 +0300 |
commit | 0f09c51c79e5c94308c7ab784ca3b8c81c8ab388 (patch) | |
tree | d9ebe690015b7dc92c340bba6e4ba1e1c9ec958d | |
parent | 817457c56a3ba0b3630e27ca1ba6cd8b8e5d1c0d (diff) | |
download | linux-0f09c51c79e5c94308c7ab784ca3b8c81c8ab388.tar.xz |
ASD Prevent TDI remaining bits to be override during JTAG xfer
JTAG xfer length is measured in bits and it is allowed to send non 8-bit
aligned xfers. For such xfers we will read the content of the remaining
bits in the last byte of tdi buffer and restore those bits along with
the xfer readback.
Add also linux types to JTAG header to remove external dependencies.
Test:
SPR ASD Sanity and jtag_test finished successfully.
SKX ASD Sanity and jtag_test finished successfully.
Change-Id: I6d53349a724c66d08b6cbbaeac166c4857835b55
Signed-off-by: Ernesto Corona <ernesto.corona@intel.com>
-rw-r--r-- | drivers/jtag/jtag.c | 18 | ||||
-rw-r--r-- | include/uapi/linux/jtag.h | 3 |
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c index 39a4d88a9c21..d4f0250d56be 100644 --- a/drivers/jtag/jtag.c +++ b/drivers/jtag/jtag.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/rtnetlink.h> #include <linux/spinlock.h> -#include <linux/types.h> #include <uapi/linux/jtag.h> struct jtag { @@ -89,6 +88,10 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case JTAG_IOCXFER: + { + u8 ubit_mask = GENMASK(7, 0); + u8 remaining_bits = 0x0; + if (copy_from_user(&xfer, (const void __user *)arg, sizeof(struct jtag_xfer))) return -EFAULT; @@ -110,6 +113,14 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); + + /* Save unused remaining bits in this transfer */ + if ((xfer.length % BITS_PER_BYTE)) { + ubit_mask = GENMASK((xfer.length % BITS_PER_BYTE) - 1, + 0); + remaining_bits = xfer_data[data_size - 1] & ~ubit_mask; + } + if (IS_ERR(xfer_data)) return -EFAULT; @@ -119,6 +130,10 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return err; } + /* Restore unused remaining bits in this transfer */ + xfer_data[data_size - 1] = (xfer_data[data_size - 1] + & ubit_mask) | remaining_bits; + err = copy_to_user(u64_to_user_ptr(xfer.tdio), (void *)xfer_data, data_size); kfree(xfer_data); @@ -129,6 +144,7 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) sizeof(struct jtag_xfer))) return -EFAULT; break; + } case JTAG_GIOCSTATUS: err = jtag->ops->status_get(jtag, &value); diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h index 220ffabe81cd..256ec7231629 100644 --- a/include/uapi/linux/jtag.h +++ b/include/uapi/linux/jtag.h @@ -6,6 +6,9 @@ #ifndef __UAPI_LINUX_JTAG_H #define __UAPI_LINUX_JTAG_H +#include <linux/types.h> +#include <linux/ioctl.h> + /* * JTAG_XFER_MODE: JTAG transfer mode. Used to set JTAG controller transfer mode * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE |