[PATCH] v4l2-compliance: detect no-mmu systems

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Check if the OS has an MMU. If not, then skip tests that only work for
systems that have an MMU.

The safest and most generic method I found is the FIONBIO ioctl that is
available for any file descriptor and is a write-only ioctl, so no memory
will be accidentally written. On a MMU system this will return EFAULT, and
on a ucLinux system this will return 0.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx>
---
Dillon, the original RFC patch (1) I posted to fix this in the kernel is not
the correct method. See:

https://stackoverflow.com/questions/24755103/how-to-handle-null-pointer-argument-to-ioctl-system-call

So instead I try to detect if there is an MMU in v4l2-compliance and, if not,
just skip those tests that require an MMU.

Can you test this patch?

Thanks!

	Hans

1: https://patchwork.linuxtv.org/project/linux-media/patch/3acd9ee4-5a58-6ed4-17fe-61596a5252b8@xxxxxxxxx/
---
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index 0eeabb2d..c53a55ba 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -88,6 +88,7 @@ bool is_vivid;
 bool is_uvcvideo;
 int media_fd = -1;
 unsigned warnings;
+bool has_mmu = true;

 static unsigned color_component;
 static unsigned color_skip;
@@ -152,8 +153,21 @@ static struct option long_options[] = {

 static void print_sha()
 {
+	int fd = open("/dev/null", O_RDONLY);
+
+	if (fd >= 0) {
+		// FIONBIO is a write-only ioctl that takes an int argument that
+		// enables (!= 0) or disables (== 0) nonblocking mode of a fd.
+		//
+		// Passing a nullptr should return EFAULT on MMU capable machines,
+		// and it works if there is no MMU.
+		has_mmu = ioctl(fd, FIONBIO, nullptr);
+		close(fd);
+	}
 	printf("v4l2-compliance %s%s, ", PACKAGE_VERSION, STRING(GIT_COMMIT_CNT));
-	printf("%zd bits, %zd-bit time_t\n", sizeof(void *) * 8, sizeof(time_t) * 8);
+	printf("%zd bits, %zd-bit time_t%s\n",
+	       sizeof(void *) * 8, sizeof(time_t) * 8,
+	       has_mmu ? "" : ", has no MMU");
 	if (strlen(STRING(GIT_SHA)))
 		printf("v4l2-compliance SHA: %s %s\n",
 		       STRING(GIT_SHA), STRING(GIT_COMMIT_DATE));
@@ -623,9 +637,9 @@ static int testCap(struct node *node)
 		V4L2_CAP_VIDEO_M2M;

 	memset(&vcap, 0xff, sizeof(vcap));
-	// Must always be there
-	fail_on_test(doioctl(node, VIDIOC_QUERYCAP, nullptr) != EFAULT);
 	fail_on_test(doioctl(node, VIDIOC_QUERYCAP, &vcap));
+	if (has_mmu)
+		fail_on_test(doioctl(node, VIDIOC_QUERYCAP, nullptr) != EFAULT);
 	fail_on_test(check_ustring(vcap.driver, sizeof(vcap.driver)));
 	fail_on_test(check_ustring(vcap.card, sizeof(vcap.card)));
 	fail_on_test(check_ustring(vcap.bus_info, sizeof(vcap.bus_info)));
@@ -988,11 +1002,10 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
 	}

 	if (driver.empty())
-		printf("Compliance test for device %s%s:\n\n",
-		       node.device, node.g_direct() ? "" : " (using libv4l2)");
+		printf("Compliance test for device ");
 	else
-		printf("Compliance test for %s device %s%s:\n\n",
-		       driver.c_str(), node.device, node.g_direct() ? "" : " (using libv4l2)");
+		printf("Compliance test for %s device ", driver.c_str());
+	printf("%s%s:\n\n", node.device, node.g_direct() ? "" : " (using libv4l2)");

 	if (node.g_caps() & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
 			 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_SLICED_VBI_CAPTURE |
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index e73ebdd3..7255161f 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -58,6 +58,7 @@ extern bool is_uvcvideo; // We're testing the uvc driver
 extern int kernel_version;
 extern int media_fd;
 extern unsigned warnings;
+extern bool has_mmu;

 enum poll_mode {
 	POLL_MODE_NONE,
diff --git a/utils/v4l2-compliance/v4l2-test-io-config.cpp b/utils/v4l2-compliance/v4l2-test-io-config.cpp
index 6f2a9ba9..dcab40b8 100644
--- a/utils/v4l2-compliance/v4l2-test-io-config.cpp
+++ b/utils/v4l2-compliance/v4l2-test-io-config.cpp
@@ -577,6 +577,8 @@ static int checkEdid(struct node *node, unsigned pad, bool is_input)
 		fail_on_test(edid.blocks == 0 || edid.blocks >= 256);
 		fail_on_test(edid.pad != pad);
 	}
+	if (!has_mmu)
+		return 0;
 	edid.blocks = 1;
 	edid.pad = pad;
 	edid.edid = nullptr;
diff --git a/utils/v4l2-compliance/v4l2-test-media.cpp b/utils/v4l2-compliance/v4l2-test-media.cpp
index ef2982c0..28af0d83 100644
--- a/utils/v4l2-compliance/v4l2-test-media.cpp
+++ b/utils/v4l2-compliance/v4l2-test-media.cpp
@@ -32,8 +32,9 @@ int testMediaDeviceInfo(struct node *node)
 	struct media_device_info mdinfo;

 	memset(&mdinfo, 0xff, sizeof(mdinfo));
-	fail_on_test(doioctl(node, MEDIA_IOC_DEVICE_INFO, nullptr) != EFAULT);
 	fail_on_test(doioctl(node, MEDIA_IOC_DEVICE_INFO, &mdinfo));
+	if (has_mmu)
+		fail_on_test(doioctl(node, MEDIA_IOC_DEVICE_INFO, nullptr) != EFAULT);
 	fail_on_test(check_0(mdinfo.reserved, sizeof(mdinfo.reserved)));
 	fail_on_test(check_string(mdinfo.driver, sizeof(mdinfo.driver)));
 	fail_on_test(mdinfo.model[0] && check_string(mdinfo.model, sizeof(mdinfo.model)));
@@ -127,21 +128,23 @@ int testMediaTopology(struct node *node)
 	fail_on_test(topology.reserved2);
 	fail_on_test(topology.reserved3);
 	fail_on_test(topology.reserved4);
-	topology.ptr_entities = 4;
-	fail_on_test(doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
-	topology.ptr_entities = 0;
-	topology.ptr_interfaces = 4;
-	fail_on_test(topology.num_interfaces &&
-		     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
-	topology.ptr_interfaces = 0;
-	topology.ptr_pads = 4;
-	fail_on_test(topology.num_pads &&
-		     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
-	topology.ptr_pads = 0;
-	topology.ptr_links = 4;
-	fail_on_test(topology.num_links &&
-		     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
-	topology.ptr_links = 0;
+	if (has_mmu) {
+		topology.ptr_entities = 4;
+		fail_on_test(doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
+		topology.ptr_entities = 0;
+		topology.ptr_interfaces = 4;
+		fail_on_test(topology.num_interfaces &&
+			     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
+		topology.ptr_interfaces = 0;
+		topology.ptr_pads = 4;
+		fail_on_test(topology.num_pads &&
+			     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
+		topology.ptr_pads = 0;
+		topology.ptr_links = 4;
+		fail_on_test(topology.num_links &&
+			     doioctl(node, MEDIA_IOC_G_TOPOLOGY, &topology) != EFAULT);
+		topology.ptr_links = 0;
+	}
 	v2_ents = new media_v2_entity[topology.num_entities];
 	memset(v2_ents, 0xff, topology.num_entities * sizeof(*v2_ents));
 	topology.ptr_entities = (uintptr_t)v2_ents;
@@ -394,12 +397,14 @@ int testMediaEnum(struct node *node)
 		fail_on_test(links.entity != ent.id);
 		fail_on_test(links.pads);
 		fail_on_test(links.links);
-		links.pads = (struct media_pad_desc *)4;
-		fail_on_test(ent.pads && doioctl(node, MEDIA_IOC_ENUM_LINKS, &links) != EFAULT);
-		links.pads = nullptr;
-		links.links = (struct media_link_desc *)4;
-		fail_on_test(ent.links && doioctl(node, MEDIA_IOC_ENUM_LINKS, &links) != EFAULT);
-		links.links = nullptr;
+		if (has_mmu) {
+			links.pads = (struct media_pad_desc *)4;
+			fail_on_test(ent.pads && doioctl(node, MEDIA_IOC_ENUM_LINKS, &links) != EFAULT);
+			links.pads = nullptr;
+			links.links = (struct media_link_desc *)4;
+			fail_on_test(ent.links && doioctl(node, MEDIA_IOC_ENUM_LINKS, &links) != EFAULT);
+			links.links = nullptr;
+		}
 		links.pads = new media_pad_desc[ent.pads];
 		memset(links.pads, 0xff, ent.pads * sizeof(*links.pads));
 		links.links = new media_link_desc[ent.links];
diff --git a/utils/v4l2-compliance/v4l2-test-subdevs.cpp b/utils/v4l2-compliance/v4l2-test-subdevs.cpp
index 68f97205..f3d85771 100644
--- a/utils/v4l2-compliance/v4l2-test-subdevs.cpp
+++ b/utils/v4l2-compliance/v4l2-test-subdevs.cpp
@@ -33,8 +33,9 @@ int testSubDevCap(struct node *node)

 	memset(&caps, 0xff, sizeof(caps));
 	// Must always be there
-	fail_on_test(doioctl(node, VIDIOC_SUBDEV_QUERYCAP, nullptr) != EFAULT);
 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_QUERYCAP, &caps));
+	if (has_mmu)
+		fail_on_test(doioctl(node, VIDIOC_SUBDEV_QUERYCAP, nullptr) != EFAULT);
 	fail_on_test(check_0(caps.reserved, sizeof(caps.reserved)));
 	fail_on_test((caps.version >> 16) < 5);
 	fail_on_test(caps.capabilities & ~VALID_SUBDEV_CAPS);



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux