Commit d6c338a7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML updates from Richard Weinberger:

 - Support for VMAP_STACK

 - Support for splice_write in hostfs

 - Fixes for virt-pci

 - Fixes for virtio_uml

 - Various fixes

* tag 'for-linus-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: fix stub location calculation
  um: virt-pci: fix uapi documentation
  um: enable VMAP_STACK
  um: virt-pci: don't do DMA from stack
  hostfs: support splice_write
  um: virtio_uml: fix memory leak on init failures
  um: virtio_uml: include linux/virtio-uml.h
  lib/logic_iomem: fix sparse warnings
  um: make PCI emulation driver init/exit static
parents 35776f10 adf9ae0d
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ config UML
	select SET_FS
	select SET_FS
	select TRACE_IRQFLAGS_SUPPORT
	select TRACE_IRQFLAGS_SUPPORT
	select TTY # Needed for line.c
	select TTY # Needed for line.c
	select HAVE_ARCH_VMAP_STACK


config MMU
config MMU
	bool
	bool
+80 −28
Original line number Original line Diff line number Diff line
@@ -56,6 +56,13 @@ static unsigned long um_pci_msi_used[BITS_TO_LONGS(MAX_MSI_VECTORS)];


#define UM_VIRT_PCI_MAXDELAY 40000
#define UM_VIRT_PCI_MAXDELAY 40000


struct um_pci_message_buffer {
	struct virtio_pcidev_msg hdr;
	u8 data[8];
};

static struct um_pci_message_buffer __percpu *um_pci_msg_bufs;

static int um_pci_send_cmd(struct um_pci_device *dev,
static int um_pci_send_cmd(struct um_pci_device *dev,
			   struct virtio_pcidev_msg *cmd,
			   struct virtio_pcidev_msg *cmd,
			   unsigned int cmd_size,
			   unsigned int cmd_size,
@@ -68,11 +75,12 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
		[1] = extra ? &extra_sg : &in_sg,
		[1] = extra ? &extra_sg : &in_sg,
		[2] = extra ? &in_sg : NULL,
		[2] = extra ? &in_sg : NULL,
	};
	};
	struct um_pci_message_buffer *buf;
	int delay_count = 0;
	int delay_count = 0;
	int ret, len;
	int ret, len;
	bool posted;
	bool posted;


	if (WARN_ON(cmd_size < sizeof(*cmd)))
	if (WARN_ON(cmd_size < sizeof(*cmd) || cmd_size > sizeof(*buf)))
		return -EINVAL;
		return -EINVAL;


	switch (cmd->op) {
	switch (cmd->op) {
@@ -88,6 +96,9 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
		break;
		break;
	}
	}


	buf = get_cpu_var(um_pci_msg_bufs);
	memcpy(buf, cmd, cmd_size);

	if (posted) {
	if (posted) {
		u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC);
		u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC);


@@ -102,7 +113,10 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
		} else {
		} else {
			/* try without allocating memory */
			/* try without allocating memory */
			posted = false;
			posted = false;
			cmd = (void *)buf;
		}
		}
	} else {
		cmd = (void *)buf;
	}
	}


	sg_init_one(&out_sg, cmd, cmd_size);
	sg_init_one(&out_sg, cmd, cmd_size);
@@ -118,11 +132,12 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
				posted ? cmd : HANDLE_NO_FREE(cmd),
				posted ? cmd : HANDLE_NO_FREE(cmd),
				GFP_ATOMIC);
				GFP_ATOMIC);
	if (ret)
	if (ret)
		return ret;
		goto out;


	if (posted) {
	if (posted) {
		virtqueue_kick(dev->cmd_vq);
		virtqueue_kick(dev->cmd_vq);
		return 0;
		ret = 0;
		goto out;
	}
	}


	/* kick and poll for getting a response on the queue */
	/* kick and poll for getting a response on the queue */
@@ -148,6 +163,8 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
	}
	}
	clear_bit(UM_PCI_STAT_WAITING, &dev->status);
	clear_bit(UM_PCI_STAT_WAITING, &dev->status);


out:
	put_cpu_var(um_pci_msg_bufs);
	return ret;
	return ret;
}
}


@@ -161,12 +178,17 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
		.size = size,
		.size = size,
		.addr = offset,
		.addr = offset,
	};
	};
	/* maximum size - we may only use parts of it */
	/* buf->data is maximum size - we may only use parts of it */
	u8 data[8];
	struct um_pci_message_buffer *buf;
	u8 *data;
	unsigned long ret = ~0ULL;


	if (!dev)
	if (!dev)
		return ~0ULL;
		return ~0ULL;


	buf = get_cpu_var(um_pci_msg_bufs);
	data = buf->data;

	memset(data, 0xff, sizeof(data));
	memset(data, 0xff, sizeof(data));


	switch (size) {
	switch (size) {
@@ -179,27 +201,34 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
		break;
		break;
	default:
	default:
		WARN(1, "invalid config space read size %d\n", size);
		WARN(1, "invalid config space read size %d\n", size);
		return ~0ULL;
		goto out;
	}
	}


	if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0,
	if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, data, 8))
			    data, sizeof(data)))
		goto out;
		return ~0ULL;


	switch (size) {
	switch (size) {
	case 1:
	case 1:
		return data[0];
		ret = data[0];
		break;
	case 2:
	case 2:
		return le16_to_cpup((void *)data);
		ret = le16_to_cpup((void *)data);
		break;
	case 4:
	case 4:
		return le32_to_cpup((void *)data);
		ret = le32_to_cpup((void *)data);
		break;
#ifdef CONFIG_64BIT
#ifdef CONFIG_64BIT
	case 8:
	case 8:
		return le64_to_cpup((void *)data);
		ret = le64_to_cpup((void *)data);
		break;
#endif
#endif
	default:
	default:
		return ~0ULL;
		break;
	}
	}

out:
	put_cpu_var(um_pci_msg_bufs);
	return ret;
}
}


static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size,
static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size,
@@ -272,8 +301,13 @@ static void um_pci_bar_copy_from(void *priv, void *buffer,
static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
				     int size)
				     int size)
{
{
	/* maximum size - we may only use parts of it */
	/* buf->data is maximum size - we may only use parts of it */
	u8 data[8];
	struct um_pci_message_buffer *buf;
	u8 *data;
	unsigned long ret = ~0ULL;

	buf = get_cpu_var(um_pci_msg_bufs);
	data = buf->data;


	switch (size) {
	switch (size) {
	case 1:
	case 1:
@@ -285,25 +319,33 @@ static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
		break;
		break;
	default:
	default:
		WARN(1, "invalid config space read size %d\n", size);
		WARN(1, "invalid config space read size %d\n", size);
		return ~0ULL;
		goto out;
	}
	}


	um_pci_bar_copy_from(priv, data, offset, size);
	um_pci_bar_copy_from(priv, data, offset, size);


	switch (size) {
	switch (size) {
	case 1:
	case 1:
		return data[0];
		ret = data[0];
		break;
	case 2:
	case 2:
		return le16_to_cpup((void *)data);
		ret = le16_to_cpup((void *)data);
		break;
	case 4:
	case 4:
		return le32_to_cpup((void *)data);
		ret = le32_to_cpup((void *)data);
		break;
#ifdef CONFIG_64BIT
#ifdef CONFIG_64BIT
	case 8:
	case 8:
		return le64_to_cpup((void *)data);
		ret = le64_to_cpup((void *)data);
		break;
#endif
#endif
	default:
	default:
		return ~0ULL;
		break;
	}
	}

out:
	put_cpu_var(um_pci_msg_bufs);
	return ret;
}
}


static void um_pci_bar_copy_to(void *priv, unsigned int offset,
static void um_pci_bar_copy_to(void *priv, unsigned int offset,
@@ -810,7 +852,7 @@ void *pci_root_bus_fwnode(struct pci_bus *bus)
	return um_pci_fwnode;
	return um_pci_fwnode;
}
}


int um_pci_init(void)
static int um_pci_init(void)
{
{
	int err, i;
	int err, i;


@@ -823,10 +865,16 @@ int um_pci_init(void)
		 "No virtio device ID configured for PCI - no PCI support\n"))
		 "No virtio device ID configured for PCI - no PCI support\n"))
		return 0;
		return 0;


	bridge = pci_alloc_host_bridge(0);
	um_pci_msg_bufs = alloc_percpu(struct um_pci_message_buffer);
	if (!bridge)
	if (!um_pci_msg_bufs)
		return -ENOMEM;
		return -ENOMEM;


	bridge = pci_alloc_host_bridge(0);
	if (!bridge) {
		err = -ENOMEM;
		goto free;
	}

	um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci");
	um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci");
	if (!um_pci_fwnode) {
	if (!um_pci_fwnode) {
		err = -ENOMEM;
		err = -ENOMEM;
@@ -878,18 +926,22 @@ int um_pci_init(void)
		irq_domain_remove(um_pci_inner_domain);
		irq_domain_remove(um_pci_inner_domain);
	if (um_pci_fwnode)
	if (um_pci_fwnode)
		irq_domain_free_fwnode(um_pci_fwnode);
		irq_domain_free_fwnode(um_pci_fwnode);
	if (bridge) {
		pci_free_resource_list(&bridge->windows);
		pci_free_resource_list(&bridge->windows);
		pci_free_host_bridge(bridge);
		pci_free_host_bridge(bridge);
	}
	free_percpu(um_pci_msg_bufs);
	return err;
	return err;
}
}
module_init(um_pci_init);
module_init(um_pci_init);


void um_pci_exit(void)
static void um_pci_exit(void)
{
{
	unregister_virtio_driver(&um_pci_virtio_driver);
	unregister_virtio_driver(&um_pci_virtio_driver);
	irq_domain_remove(um_pci_msi_domain);
	irq_domain_remove(um_pci_msi_domain);
	irq_domain_remove(um_pci_inner_domain);
	irq_domain_remove(um_pci_inner_domain);
	pci_free_resource_list(&bridge->windows);
	pci_free_resource_list(&bridge->windows);
	pci_free_host_bridge(bridge);
	pci_free_host_bridge(bridge);
	free_percpu(um_pci_msg_bufs);
}
}
module_exit(um_pci_exit);
module_exit(um_pci_exit);
+4 −1
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/virtio_config.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
#include <linux/virtio_ring.h>
#include <linux/time-internal.h>
#include <linux/time-internal.h>
#include <linux/virtio-uml.h>
#include <shared/as-layout.h>
#include <shared/as-layout.h>
#include <irq_kern.h>
#include <irq_kern.h>
#include <init.h>
#include <init.h>
@@ -1139,7 +1140,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
		rc = os_connect_socket(pdata->socket_path);
		rc = os_connect_socket(pdata->socket_path);
	} while (rc == -EINTR);
	} while (rc == -EINTR);
	if (rc < 0)
	if (rc < 0)
		return rc;
		goto error_free;
	vu_dev->sock = rc;
	vu_dev->sock = rc;


	spin_lock_init(&vu_dev->sock_lock);
	spin_lock_init(&vu_dev->sock_lock);
@@ -1160,6 +1161,8 @@ static int virtio_uml_probe(struct platform_device *pdev)


error_init:
error_init:
	os_close_file(vu_dev->sock);
	os_close_file(vu_dev->sock);
error_free:
	kfree(vu_dev);
	return rc;
	return rc;
}
}


+1 −2
Original line number Original line Diff line number Diff line
@@ -24,8 +24,7 @@
void __attribute__ ((__section__ (".__syscall_stub")))
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
stub_clone_handler(void)
{
{
	int stack;
	struct stub_data *data = get_stub_page();
	struct stub_data *data = (void *) ((unsigned long)&stack & ~(UM_KERN_PAGE_SIZE - 1));
	long err;
	long err;


	err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
	err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+12 −0
Original line number Original line Diff line number Diff line
@@ -101,4 +101,16 @@ static inline void remap_stack_and_trap(void)
		"memory");
		"memory");
}
}


static __always_inline void *get_stub_page(void)
{
	unsigned long ret;

	asm volatile (
		"movl %%esp,%0 ;"
		"andl %1,%0"
		: "=a" (ret)
		: "g" (~(UM_KERN_PAGE_SIZE - 1)));

	return (void *)ret;
}
#endif
#endif
Loading