This pull request contains the following changes for UML:
- Support for VMAP_STACK - Support for splice_write in hostfs - Fixes for virt-pci - Fixes for virtio_uml - Various fixes -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEdgfidid8lnn52cLTZvlZhesYu8EFAmE6Xv4WHHJpY2hhcmRA c2lnbWEtc3Rhci5hdAAKCRBm+VmF6xi7wbpMD/0UBswFdI9J6ePQf2+UyQ3sfFay xZ5/gyL+Ou0k/hwcjLx4DtIQBXkNiwgiKF+ncHvMXTr/oKAo5f7UsGYyMNIKlbKO LrIpc6avqmeovTtOuVhm6VML/m7rvJYC/wJ0VFu6CN2aELoRZLXfeogwn1beAl6p 3JKc54tbew5022lZF6Df/QEpkCyuOjWMnEn/khJGuz+vmkodV+5cegZqxJIAnWrU NVGf7laiV+rBWY4SVXiuJBGTNFwLZkORNa5evBScum85aqwaFawepZT0pNKEt4tc Lalyy7jACriWeQJeQksWACfexYFPywQU/ebYcAlQ9b0wd5aZxi8IJc9wj0a1Oz3N i2DEf09/Zk8eE1cbpp6GP+pbvlqNVsAgtLane2Wzxc1kuJGiFYeXCiDyCFzbhbxW rsTiP3oAxC7OjFwebmtCvBbK9GSl5ETDwfOg+nl2idIK0cds292ju3bWL9vO6VRP Cjxzn7ZaJYvPlrRHo5yujLURqRZSrkPcL/XthIDQJNjXMd8j2AYMRVM2n0gFLu7g jSphwg8t3SmCrolGtUucadTPNMR5pE3rQTN+tbhqwGp+Cs+MnM7CqKUv+JoRC7KF 1qH/1p9tiz/utIpjKmvNZtZRwnElBoEgyoY6RdtqlCMnDcuLpDdmCRyWDsHAzXKg 1X9ym5QqDj5zSLxsXg== =RgAO -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
d6c338a741
@ -24,6 +24,7 @@ config UML
|
||||
select SET_FS
|
||||
select TRACE_IRQFLAGS_SUPPORT
|
||||
select TTY # Needed for line.c
|
||||
select HAVE_ARCH_VMAP_STACK
|
||||
|
||||
config MMU
|
||||
bool
|
||||
|
@ -56,6 +56,13 @@ static unsigned long um_pci_msi_used[BITS_TO_LONGS(MAX_MSI_VECTORS)];
|
||||
|
||||
#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,
|
||||
struct virtio_pcidev_msg *cmd,
|
||||
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,
|
||||
[2] = extra ? &in_sg : NULL,
|
||||
};
|
||||
struct um_pci_message_buffer *buf;
|
||||
int delay_count = 0;
|
||||
int ret, len;
|
||||
bool posted;
|
||||
|
||||
if (WARN_ON(cmd_size < sizeof(*cmd)))
|
||||
if (WARN_ON(cmd_size < sizeof(*cmd) || cmd_size > sizeof(*buf)))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd->op) {
|
||||
@ -88,6 +96,9 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
buf = get_cpu_var(um_pci_msg_bufs);
|
||||
memcpy(buf, cmd, cmd_size);
|
||||
|
||||
if (posted) {
|
||||
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 {
|
||||
/* try without allocating memory */
|
||||
posted = false;
|
||||
cmd = (void *)buf;
|
||||
}
|
||||
} else {
|
||||
cmd = (void *)buf;
|
||||
}
|
||||
|
||||
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),
|
||||
GFP_ATOMIC);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
if (posted) {
|
||||
virtqueue_kick(dev->cmd_vq);
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
out:
|
||||
put_cpu_var(um_pci_msg_bufs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -161,12 +178,17 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
|
||||
.size = size,
|
||||
.addr = offset,
|
||||
};
|
||||
/* maximum size - we may only use parts of it */
|
||||
u8 data[8];
|
||||
/* buf->data is maximum size - we may only use parts of it */
|
||||
struct um_pci_message_buffer *buf;
|
||||
u8 *data;
|
||||
unsigned long ret = ~0ULL;
|
||||
|
||||
if (!dev)
|
||||
return ~0ULL;
|
||||
|
||||
buf = get_cpu_var(um_pci_msg_bufs);
|
||||
data = buf->data;
|
||||
|
||||
memset(data, 0xff, sizeof(data));
|
||||
|
||||
switch (size) {
|
||||
@ -179,27 +201,34 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
data, sizeof(data)))
|
||||
return ~0ULL;
|
||||
if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, data, 8))
|
||||
goto out;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
return data[0];
|
||||
ret = data[0];
|
||||
break;
|
||||
case 2:
|
||||
return le16_to_cpup((void *)data);
|
||||
ret = le16_to_cpup((void *)data);
|
||||
break;
|
||||
case 4:
|
||||
return le32_to_cpup((void *)data);
|
||||
ret = le32_to_cpup((void *)data);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
return le64_to_cpup((void *)data);
|
||||
ret = le64_to_cpup((void *)data);
|
||||
break;
|
||||
#endif
|
||||
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,
|
||||
@ -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,
|
||||
int size)
|
||||
{
|
||||
/* maximum size - we may only use parts of it */
|
||||
u8 data[8];
|
||||
/* buf->data is maximum size - we may only use parts of it */
|
||||
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) {
|
||||
case 1:
|
||||
@ -285,25 +319,33 @@ static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
|
||||
break;
|
||||
default:
|
||||
WARN(1, "invalid config space read size %d\n", size);
|
||||
return ~0ULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
um_pci_bar_copy_from(priv, data, offset, size);
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
return data[0];
|
||||
ret = data[0];
|
||||
break;
|
||||
case 2:
|
||||
return le16_to_cpup((void *)data);
|
||||
ret = le16_to_cpup((void *)data);
|
||||
break;
|
||||
case 4:
|
||||
return le32_to_cpup((void *)data);
|
||||
ret = le32_to_cpup((void *)data);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
return le64_to_cpup((void *)data);
|
||||
ret = le64_to_cpup((void *)data);
|
||||
break;
|
||||
#endif
|
||||
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,
|
||||
@ -810,7 +852,7 @@ void *pci_root_bus_fwnode(struct pci_bus *bus)
|
||||
return um_pci_fwnode;
|
||||
}
|
||||
|
||||
int um_pci_init(void)
|
||||
static int um_pci_init(void)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
@ -823,10 +865,16 @@ int um_pci_init(void)
|
||||
"No virtio device ID configured for PCI - no PCI support\n"))
|
||||
return 0;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
um_pci_msg_bufs = alloc_percpu(struct um_pci_message_buffer);
|
||||
if (!um_pci_msg_bufs)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge) {
|
||||
err = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci");
|
||||
if (!um_pci_fwnode) {
|
||||
err = -ENOMEM;
|
||||
@ -878,18 +926,22 @@ free:
|
||||
irq_domain_remove(um_pci_inner_domain);
|
||||
if (um_pci_fwnode)
|
||||
irq_domain_free_fwnode(um_pci_fwnode);
|
||||
if (bridge) {
|
||||
pci_free_resource_list(&bridge->windows);
|
||||
pci_free_host_bridge(bridge);
|
||||
}
|
||||
free_percpu(um_pci_msg_bufs);
|
||||
return err;
|
||||
}
|
||||
module_init(um_pci_init);
|
||||
|
||||
void um_pci_exit(void)
|
||||
static void um_pci_exit(void)
|
||||
{
|
||||
unregister_virtio_driver(&um_pci_virtio_driver);
|
||||
irq_domain_remove(um_pci_msi_domain);
|
||||
irq_domain_remove(um_pci_inner_domain);
|
||||
pci_free_resource_list(&bridge->windows);
|
||||
pci_free_host_bridge(bridge);
|
||||
free_percpu(um_pci_msg_bufs);
|
||||
}
|
||||
module_exit(um_pci_exit);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <linux/time-internal.h>
|
||||
#include <linux/virtio-uml.h>
|
||||
#include <shared/as-layout.h>
|
||||
#include <irq_kern.h>
|
||||
#include <init.h>
|
||||
@ -1139,7 +1140,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
|
||||
rc = os_connect_socket(pdata->socket_path);
|
||||
} while (rc == -EINTR);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto error_free;
|
||||
vu_dev->sock = rc;
|
||||
|
||||
spin_lock_init(&vu_dev->sock_lock);
|
||||
@ -1160,6 +1161,8 @@ static int virtio_uml_probe(struct platform_device *pdev)
|
||||
|
||||
error_init:
|
||||
os_close_file(vu_dev->sock);
|
||||
error_free:
|
||||
kfree(vu_dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@
|
||||
void __attribute__ ((__section__ (".__syscall_stub")))
|
||||
stub_clone_handler(void)
|
||||
{
|
||||
int stack;
|
||||
struct stub_data *data = (void *) ((unsigned long)&stack & ~(UM_KERN_PAGE_SIZE - 1));
|
||||
struct stub_data *data = get_stub_page();
|
||||
long err;
|
||||
|
||||
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
|
||||
|
@ -101,4 +101,16 @@ static inline void remap_stack_and_trap(void)
|
||||
"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
|
||||
|
@ -108,4 +108,16 @@ static inline void remap_stack_and_trap(void)
|
||||
__syscall_clobber, "r10", "r8", "r9");
|
||||
}
|
||||
|
||||
static __always_inline void *get_stub_page(void)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
asm volatile (
|
||||
"movq %%rsp,%0 ;"
|
||||
"andq %1,%0"
|
||||
: "=a" (ret)
|
||||
: "g" (~(UM_KERN_PAGE_SIZE - 1)));
|
||||
|
||||
return (void *)ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -11,9 +11,8 @@
|
||||
void __attribute__ ((__section__ (".__syscall_stub")))
|
||||
stub_segv_handler(int sig, siginfo_t *info, void *p)
|
||||
{
|
||||
int stack;
|
||||
struct faultinfo *f = get_stub_page();
|
||||
ucontext_t *uc = p;
|
||||
struct faultinfo *f = (void *)(((unsigned long)&stack) & ~(UM_KERN_PAGE_SIZE - 1));
|
||||
|
||||
GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext);
|
||||
trap_myself();
|
||||
|
@ -381,6 +381,7 @@ static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
|
||||
static const struct file_operations hostfs_file_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
.mmap = generic_file_mmap,
|
||||
|
@ -9,13 +9,14 @@
|
||||
|
||||
/**
|
||||
* enum virtio_pcidev_ops - virtual PCI device operations
|
||||
* @VIRTIO_PCIDEV_OP_RESERVED: reserved to catch errors
|
||||
* @VIRTIO_PCIDEV_OP_CFG_READ: read config space, size is 1, 2, 4 or 8;
|
||||
* the @data field should be filled in by the device (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_CFG_WRITE: write config space, size is 1, 2, 4 or 8;
|
||||
* the @data field contains the data to write (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_BAR_READ: read BAR mem/pio, size can be variable;
|
||||
* @VIRTIO_PCIDEV_OP_MMIO_READ: read BAR mem/pio, size can be variable;
|
||||
* the @data field should be filled in by the device (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_BAR_WRITE: write BAR mem/pio, size can be variable;
|
||||
* @VIRTIO_PCIDEV_OP_MMIO_WRITE: write BAR mem/pio, size can be variable;
|
||||
* the @data field contains the data to write (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_MMIO_MEMSET: memset MMIO, size is variable but
|
||||
* the @data field only has one byte (unlike @VIRTIO_PCIDEV_OP_MMIO_WRITE)
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/logic_iomem.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct logic_iomem_region {
|
||||
const struct resource *res;
|
||||
@ -78,7 +79,7 @@ static void __iomem *real_ioremap(phys_addr_t offset, size_t size)
|
||||
static void real_iounmap(void __iomem *addr)
|
||||
{
|
||||
WARN(1, "invalid iounmap for addr 0x%llx\n",
|
||||
(unsigned long long)addr);
|
||||
(unsigned long long __force)addr);
|
||||
}
|
||||
#endif /* CONFIG_LOGIC_IOMEM_FALLBACK */
|
||||
|
||||
@ -172,14 +173,15 @@ EXPORT_SYMBOL(iounmap);
|
||||
static u##sz real_raw_read ## op(const volatile void __iomem *addr) \
|
||||
{ \
|
||||
WARN(1, "Invalid read" #op " at address %llx\n", \
|
||||
(unsigned long long)addr); \
|
||||
(unsigned long long __force)addr); \
|
||||
return (u ## sz)~0ULL; \
|
||||
} \
|
||||
\
|
||||
void real_raw_write ## op(u ## sz val, volatile void __iomem *addr) \
|
||||
static void real_raw_write ## op(u ## sz val, \
|
||||
volatile void __iomem *addr) \
|
||||
{ \
|
||||
WARN(1, "Invalid writeq" #op " of 0x%llx at address %llx\n", \
|
||||
(unsigned long long)val, (unsigned long long)addr); \
|
||||
(unsigned long long)val, (unsigned long long __force)addr);\
|
||||
} \
|
||||
|
||||
MAKE_FALLBACK(b, 8);
|
||||
@ -192,14 +194,14 @@ MAKE_FALLBACK(q, 64);
|
||||
static void real_memset_io(volatile void __iomem *addr, int value, size_t size)
|
||||
{
|
||||
WARN(1, "Invalid memset_io at address 0x%llx\n",
|
||||
(unsigned long long)addr);
|
||||
(unsigned long long __force)addr);
|
||||
}
|
||||
|
||||
static void real_memcpy_fromio(void *buffer, const volatile void __iomem *addr,
|
||||
size_t size)
|
||||
{
|
||||
WARN(1, "Invalid memcpy_fromio at address 0x%llx\n",
|
||||
(unsigned long long)addr);
|
||||
(unsigned long long __force)addr);
|
||||
|
||||
memset(buffer, 0xff, size);
|
||||
}
|
||||
@ -208,7 +210,7 @@ static void real_memcpy_toio(volatile void __iomem *addr, const void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
WARN(1, "Invalid memcpy_toio at address 0x%llx\n",
|
||||
(unsigned long long)addr);
|
||||
(unsigned long long __force)addr);
|
||||
}
|
||||
#endif /* CONFIG_LOGIC_IOMEM_FALLBACK */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user