summary refs log blame commit diff
path: root/pkgs/development/libraries/wlroots/0002-util-support-virtio_wl-shm-allocation.patch
blob: 2956f8222922007db4d95ba19e29b3c4f40efcf3 (plain) (tree)
1
                                                                      























































































































































































































































































                                                                                 
From 3e287337ef82eeb632bd7d67106785591351a3a8 Mon Sep 17 00:00:00 2001
From: Alyssa Ross <hi@alyssa.is>
Date: Sat, 23 May 2020 03:42:33 +0000
Subject: [PATCH 2/2] util: support virtio_wl shm allocation

---
 include/util/virtio_wl.h     | 14 ++++++
 include/util/virtio_wl_shm.h |  8 +++
 util/meson.build             |  2 +
 util/shm.c                   | 12 +++++
 util/virtio_wl.c             | 96 ++++++++++++++++++++++++++++++++++++
 util/virtio_wl_shm.c         | 65 ++++++++++++++++++++++++
 6 files changed, 197 insertions(+)
 create mode 100644 include/util/virtio_wl.h
 create mode 100644 include/util/virtio_wl_shm.h
 create mode 100644 util/virtio_wl.c
 create mode 100644 util/virtio_wl_shm.c

diff --git a/include/util/virtio_wl.h b/include/util/virtio_wl.h
new file mode 100644
index 00000000..ae5c19b5
--- /dev/null
+++ b/include/util/virtio_wl.h
@@ -0,0 +1,14 @@
+#ifndef UTIL_VIRTIO_WL_H
+#define UTIL_VIRTIO_WL_H
+
+struct virtwl_ioctl_txn;
+
+int virtio_wl_connect(const char *name, uint32_t flags);
+
+int32_t virtio_wl_sendmsg(int sockfd, struct virtwl_ioctl_txn *ioctl_txn);
+int32_t virtio_wl_send(int sockfd, const void *buf, uint32_t len);
+
+int32_t virtio_wl_recvmsg(int sockfd, struct virtwl_ioctl_txn *ioctl_txn);
+int32_t virtio_wl_recv(int sockfd, void *buf, uint32_t len);
+
+#endif
diff --git a/include/util/virtio_wl_shm.h b/include/util/virtio_wl_shm.h
new file mode 100644
index 00000000..d9f9f045
--- /dev/null
+++ b/include/util/virtio_wl_shm.h
@@ -0,0 +1,8 @@
+#ifndef UTIL_VIRTIO_WL_SHM_H
+#define UTIL_VIRTIO_WL_SHM_H
+
+#include <stddef.h>
+
+int allocate_virtio_wl_shm_file(size_t size);
+
+#endif
diff --git a/util/meson.build b/util/meson.build
index c6614275..6ec6182b 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -4,4 +4,6 @@ wlr_files += files(
 	'region.c',
 	'shm.c',
 	'signal.c',
+	'virtio_wl.c',
+	'virtio_wl_shm.c',
 )
diff --git a/util/shm.c b/util/shm.c
index f7c7303e..d8110904 100644
--- a/util/shm.c
+++ b/util/shm.c
@@ -2,11 +2,14 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <time.h>
 #include <unistd.h>
 #include <wlr/config.h>
+#include <wlr/util/log.h>
 #include "util/shm.h"
+#include "util/virtio_wl_shm.h"
 
 static void randname(char *buf) {
 	struct timespec ts;
@@ -19,6 +22,11 @@ static void randname(char *buf) {
 }
 
 int create_shm_file(void) {
+	if (getenv("WLR_VIRTIO_WL")) {
+		wlr_log(WLR_ERROR, "cannot use create_shm_file with virtio_wl");
+		return -1;
+	}
+
 	int retries = 100;
 	do {
 		char name[] = "/wlroots-XXXXXX";
@@ -37,6 +45,10 @@ int create_shm_file(void) {
 }
 
 int allocate_shm_file(size_t size) {
+	if (getenv("WLR_VIRTIO_WL")) {
+		return allocate_virtio_wl_shm_file(size);
+	}
+
 	int fd = create_shm_file();
 	if (fd < 0) {
 		return -1;
diff --git a/util/virtio_wl.c b/util/virtio_wl.c
new file mode 100644
index 00000000..e7ee58ac
--- /dev/null
+++ b/util/virtio_wl.c
@@ -0,0 +1,96 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <linux/virtwl.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "util/virtio_wl.h"
+
+// This is essentially vendored reusable library code, so I consider
+// it exempt from the wlroots style guide. :)
+
+int virtio_wl_connect(const char *name, uint32_t flags)
+{
+	static int wl_fd = -1;
+	if (wl_fd < 0)
+		wl_fd = open("/dev/wl0", O_RDWR | O_CLOEXEC);
+	if (wl_fd < 0)
+		return wl_fd;
+
+	struct virtwl_ioctl_new new_ctx = {
+		.type = name ? VIRTWL_IOCTL_NEW_CTX_NAMED : VIRTWL_IOCTL_NEW_CTX,
+		.fd = -1,
+		.flags = flags,
+	};
+	// Device assumes name 32 bytes long if not null terminated.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+	if (name)
+		strncpy(new_ctx.name, name, sizeof(new_ctx.name));
+#pragma GCC diagnostic pop
+
+	if (ioctl(wl_fd, VIRTWL_IOCTL_NEW, &new_ctx))
+		return -1;
+
+	return new_ctx.fd;
+}
+
+int32_t virtio_wl_sendmsg(int sockfd, struct virtwl_ioctl_txn *ioctl_txn)
+{
+	int r = ioctl(sockfd, VIRTWL_IOCTL_SEND, ioctl_txn);
+	if (!r)
+		r = ioctl_txn->len > INT32_MAX ? INT32_MAX : ioctl_txn->len;
+	return r;
+}
+
+int32_t virtio_wl_send(int sockfd, const void *buf, uint32_t len)
+{
+	struct virtwl_ioctl_txn *ioctl_txn = malloc(sizeof(*ioctl_txn) + len);
+	if (!ioctl_txn)
+		return -1;
+
+	for (size_t i = 0; i < VIRTWL_SEND_MAX_ALLOCS; i++)
+		ioctl_txn->fds[i] = -1;
+
+	ioctl_txn->len = len;
+	memcpy((uint8_t *)ioctl_txn + sizeof(*ioctl_txn), buf, len);
+
+	int r = virtio_wl_sendmsg(sockfd, ioctl_txn);
+
+	free(ioctl_txn);
+	return r;
+}
+
+int32_t virtio_wl_recvmsg(int sockfd, struct virtwl_ioctl_txn *ioctl_txn)
+{
+	if (ioctl(sockfd, VIRTWL_IOCTL_RECV, ioctl_txn))
+		return -1;
+
+	return ioctl_txn->len > INT32_MAX ? INT32_MAX : ioctl_txn->len;
+}
+
+int32_t virtio_wl_recv(int sockfd, void *buf, uint32_t len)
+{
+	struct virtwl_ioctl_txn *ioctl_txn = malloc(sizeof(*ioctl_txn) + len);
+	if (!ioctl_txn)
+		return -1;
+
+	ioctl_txn->len = len;
+
+	int rv = virtio_wl_recvmsg(sockfd, ioctl_txn);
+	if (rv < 0)
+		goto cleanup;
+
+	memcpy(buf, (uint8_t *)ioctl_txn + sizeof(*ioctl_txn), ioctl_txn->len);
+
+	for (size_t i = 0; i < VIRTWL_SEND_MAX_ALLOCS; i++)
+		if (ioctl_txn->fds[i] >= 0)
+			close(ioctl_txn->fds[i]);
+
+ cleanup:
+	free(ioctl_txn);
+	return rv;
+}
diff --git a/util/virtio_wl_shm.c b/util/virtio_wl_shm.c
new file mode 100644
index 00000000..b2109310
--- /dev/null
+++ b/util/virtio_wl_shm.c
@@ -0,0 +1,65 @@
+#include <assert.h>
+#include <errno.h>
+#include <linux/virtwl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util/virtio_wl.h"
+#include "util/virtio_wl_shm.h"
+
+// This is essentially vendored reusable library code, so I consider
+// it exempt from the wlroots style guide. :)
+
+int allocate_virtio_wl_shm_file(size_t size)
+{
+	static const size_t NAME_SIZE = 224;
+	static const char *NAME = "wlroots";
+
+	int r;
+	uint8_t *message = NULL;
+	struct virtwl_ioctl_txn *ioctl_txn = NULL;
+
+	int conn = virtio_wl_connect("__crosvm_memfd", 0);
+	if (conn < 0)
+		return conn;
+
+	message = calloc(NAME_SIZE + 8, 1);
+	if (!message) {
+		r = -1;
+		goto cleanup;
+	}
+	strcpy((char *)message, NAME);
+
+	// Encode size as 64-bit little-endian unsigned integer.
+	for (uint8_t i = 0; i < 8; i++)
+		message[NAME_SIZE + i] = (uint8_t)((uint64_t)size >> (8 * i));
+
+	if ((r = virtio_wl_send(conn, message, NAME_SIZE + 8)) < 0)
+		 goto cleanup;
+
+	int32_t len = 1;
+	if (!(ioctl_txn = malloc(sizeof(*ioctl_txn) + len))) {
+		r = -1;
+		goto cleanup;
+	}
+	ioctl_txn->len = len;
+
+	if ((r = virtio_wl_recvmsg(conn, ioctl_txn)) < 0)
+		goto cleanup;
+
+	if (((uint8_t *)ioctl_txn + sizeof(*ioctl_txn))[0]) {
+		// We don't actually know why we didn't get the
+		// memory, but out of memory is a reasonable guess.
+		errno = ENOMEM;
+		r = -1;
+		goto cleanup;
+	}
+
+	r = ioctl_txn->fds[0];
+	assert(r >= 0);
+
+ cleanup:
+	free(message);
+	free(ioctl_txn);
+	return r;
+}
-- 
2.26.2