iommu/iommu-debug: Add secure_attach debugfs file

It can be useful to perform tests on secure domains.  Add support for
this with a "secure_attach" file that will also set the
DOMAIN_ATTR_SECURE_VMID to the value written to the file.

Example usage:

    # cd /sys/kernel/debug/iommu/tests/<device>
    # echo 0xA > secure_attach
    # echo 0x1000,0x1000,0x1000,1 > map
    # echo 0x1000,0x1000 > unmap
    # echo 0 > secure_attach

Change-Id: I0181e360f3e98e0e47a3af8c6adb71c9c4a3c9b5
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 0827a49..4ecfb79 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -475,7 +475,8 @@
 	.release = single_release,
 };
 
-static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev)
+static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
+					int val, bool is_secure)
 {
 	ddev->domain = iommu_domain_alloc(&platform_bus_type);
 	if (!ddev->domain) {
@@ -483,6 +484,13 @@
 		return -ENOMEM;
 	}
 
+	if (is_secure && iommu_domain_set_attr(ddev->domain,
+					       DOMAIN_ATTR_SECURE_VMID,
+					       &val)) {
+		pr_err("Couldn't set secure vmid to %d\n", val);
+		goto out_domain_free;
+	}
+
 	if (iommu_attach_device(ddev->domain, ddev->dev)) {
 		pr_err("Couldn't attach new domain to device. Is it already attached?\n");
 		goto out_domain_free;
@@ -496,27 +504,22 @@
 	return -EIO;
 }
 
-static ssize_t iommu_debug_attach_write(struct file *file,
-				      const char __user *ubuf,
-				      size_t count, loff_t *offset)
+static ssize_t __iommu_debug_attach_write(struct file *file,
+					  const char __user *ubuf,
+					  size_t count, loff_t *offset,
+					  bool is_secure)
 {
 	struct iommu_debug_device *ddev = file->private_data;
 	ssize_t retval;
-	char val;
+	int val;
 
-	if (count > 2) {
-		pr_err("Invalid value.  Expected 0 or 1.\n");
-		retval = -EINVAL;
-		goto out;
-	}
-
-	if (copy_from_user(&val, ubuf, 1)) {
-		pr_err("Couldn't copy from user\n");
+	if (kstrtoint_from_user(ubuf, count, 0, &val)) {
+		pr_err("Invalid format. Expected a hex or decimal integer");
 		retval = -EFAULT;
 		goto out;
 	}
 
-	if (val == '1') {
+	if (val) {
 		if (ddev->domain) {
 			pr_err("Already attached.\n");
 			retval = -EINVAL;
@@ -527,12 +530,12 @@
 			retval = -EINVAL;
 			goto out;
 		}
-		if (iommu_debug_attach_do_attach(ddev)) {
+		if (iommu_debug_attach_do_attach(ddev, val, is_secure)) {
 			retval = -EIO;
 			goto out;
 		}
 		pr_err("Attached\n");
-	} else if (val == '0') {
+	} else {
 		if (!ddev->domain) {
 			pr_err("No domain. Did you already attach?\n");
 			retval = -EINVAL;
@@ -542,10 +545,6 @@
 		iommu_domain_free(ddev->domain);
 		ddev->domain = NULL;
 		pr_err("Detached\n");
-	} else {
-		pr_err("Invalid value.  Expected 0 or 1\n");
-		retval = -EFAULT;
-		goto out;
 	}
 
 	retval = count;
@@ -553,6 +552,15 @@
 	return retval;
 }
 
+static ssize_t iommu_debug_attach_write(struct file *file,
+					  const char __user *ubuf,
+					  size_t count, loff_t *offset)
+{
+	return __iommu_debug_attach_write(file, ubuf, count, offset,
+					  false);
+
+}
+
 static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
 				       size_t count, loff_t *offset)
 {
@@ -579,6 +587,21 @@
 	.read	= iommu_debug_attach_read,
 };
 
+static ssize_t iommu_debug_attach_write_secure(struct file *file,
+					       const char __user *ubuf,
+					       size_t count, loff_t *offset)
+{
+	return __iommu_debug_attach_write(file, ubuf, count, offset,
+					  true);
+
+}
+
+static const struct file_operations iommu_debug_secure_attach_fops = {
+	.open	= simple_open,
+	.write	= iommu_debug_attach_write_secure,
+	.read	= iommu_debug_attach_read,
+};
+
 static ssize_t iommu_debug_atos_write(struct file *file,
 				      const char __user *ubuf,
 				      size_t count, loff_t *offset)
@@ -823,6 +846,13 @@
 		goto err_rmdir;
 	}
 
+	if (!debugfs_create_file("secure_attach", S_IRUSR, dir, ddev,
+				 &iommu_debug_secure_attach_fops)) {
+		pr_err("Couldn't create iommu/devices/%s/secure_attach debugfs file\n",
+		       dev_name(dev));
+		goto err_rmdir;
+	}
+
 	if (!debugfs_create_file("atos", S_IWUSR, dir, ddev,
 				 &iommu_debug_atos_fops)) {
 		pr_err("Couldn't create iommu/devices/%s/atos debugfs file\n",