summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErnesto Corona <ernesto.corona@intel.com>2021-03-04 03:11:47 +0300
committerJae Hyun Yoo <jae.hyun.yoo@linux.intel.com>2021-10-20 01:10:38 +0300
commit98b171955ae9f0860fc3313fddf4d081e8517b57 (patch)
tree975d83cf98f84eb09eaf7887778e571d9183b893
parent1339fd49198b56afed1d3dd6c85f394112d1b100 (diff)
downloadlinux-98b171955ae9f0860fc3313fddf4d081e8517b57.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. Signed-off-by: Ernesto Corona <ernesto.corona@intel.com>
-rw-r--r--drivers/jtag/jtag.c18
-rw-r--r--include/uapi/linux/jtag.h3
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