Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull UML updates from Richard Weinberger:

- Support for optimized routines based on the host CPU

- Support for PCI via virtio

- Various fixes

* tag 'for-linus-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
um: remove unneeded semicolon in um_arch.c
um: Remove the repeated declaration
um: fix error return code in winch_tramp()
um: fix error return code in slip_open()
um: Fix stack pointer alignment
um: implement flush_cache_vmap/flush_cache_vunmap
um: add a UML specific futex implementation
um: enable the use of optimized xor routines in UML
um: Add support for host CPU flags and alignment
um: allow not setting extra rpaths in the linux binary
um: virtio/pci: enable suspend/resume
um: add PCI over virtio emulation driver
um: irqs: allow invoking time-travel handler multiple times
um: time-travel/signals: fix ndelay() in interrupt
um: expose time-travel mode to userspace side
um: export signals_enabled directly
um: remove unused smp_sigio_handler() declaration
lib: add iomem emulation (logic_iomem)
um: allow disabling NO_IOMEM

+2211 -111
+32 -1
arch/um/Kconfig
··· 15 15 select HAVE_FUTEX_CMPXCHG if FUTEX 16 16 select HAVE_DEBUG_KMEMLEAK 17 17 select HAVE_DEBUG_BUGVERBOSE 18 - select NO_DMA 18 + select NO_DMA if !UML_DMA_EMULATION 19 19 select GENERIC_IRQ_SHOW 20 20 select GENERIC_CPU_DEVICES 21 21 select HAVE_GCC_PLUGINS ··· 26 26 bool 27 27 default y 28 28 29 + config UML_DMA_EMULATION 30 + bool 31 + 29 32 config NO_IOMEM 33 + bool "disable IOMEM" if EXPERT 34 + depends on !INDIRECT_IOMEM 35 + default y 36 + 37 + config UML_IOMEM_EMULATION 38 + bool 39 + select INDIRECT_IOMEM 40 + select GENERIC_PCI_IOMAP 41 + select GENERIC_IOMAP 42 + select NO_GENERIC_PCI_IOPORT_MAP 43 + 44 + config NO_IOPORT_MAP 30 45 def_bool y 31 46 32 47 config ISA ··· 76 61 range 1 1 77 62 default 1 78 63 64 + config ARCH_HAS_CACHE_LINE_SIZE 65 + def_bool y 66 + 79 67 source "arch/$(HEADER_ARCH)/um/Kconfig" 80 68 81 69 config MAY_HAVE_RUNTIME_DEPS ··· 108 90 default y 109 91 depends on !LD_SCRIPT_STATIC 110 92 select MODULE_REL_CRCS if MODVERSIONS 93 + 94 + config LD_SCRIPT_DYN_RPATH 95 + bool "set rpath in the binary" if EXPERT 96 + default y 97 + depends on LD_SCRIPT_DYN 98 + help 99 + Add /lib (and /lib64 for 64-bit) to the linux binary's rpath 100 + explicitly. 101 + 102 + You may need to turn this off if compiling for nix systems 103 + that have their libraries in random /nix directories and 104 + might otherwise unexpected use libraries from /lib or /lib64 105 + instead of the desired ones. 111 106 112 107 config HOSTFS 113 108 tristate "Host filesystem"
+2 -1
arch/um/Makefile
··· 118 118 $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h 119 119 120 120 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static 121 - LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie) 121 + LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) 122 + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib 122 123 123 124 CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ 124 125 -fno-stack-protector $(call cc-option, -fno-stack-protector-all)
+20
arch/um/drivers/Kconfig
··· 357 357 rtcwake, especially in time-travel mode. This driver enables that 358 358 by providing a fake RTC clock that causes a wakeup at the right 359 359 time. 360 + 361 + config UML_PCI_OVER_VIRTIO 362 + bool "Enable PCI over VIRTIO device simulation" 363 + # in theory, just VIRTIO is enough, but that causes recursion 364 + depends on VIRTIO_UML 365 + select FORCE_PCI 366 + select UML_IOMEM_EMULATION 367 + select UML_DMA_EMULATION 368 + select PCI_MSI 369 + select PCI_MSI_IRQ_DOMAIN 370 + select PCI_LOCKLESS_CONFIG 371 + 372 + config UML_PCI_OVER_VIRTIO_DEVICE_ID 373 + int "set the virtio device ID for PCI emulation" 374 + default -1 375 + depends on UML_PCI_OVER_VIRTIO 376 + help 377 + There's no official device ID assigned (yet), set the one you 378 + wish to use for experimentation here. The default of -1 is 379 + not valid and will cause the driver to fail at probe.
+1
arch/um/drivers/Makefile
··· 64 64 obj-$(CONFIG_UML_RANDOM) += random.o 65 65 obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o 66 66 obj-$(CONFIG_UML_RTC) += rtc.o 67 + obj-$(CONFIG_UML_PCI_OVER_VIRTIO) += virt-pci.o 67 68 68 69 # pcap_user.o must be added explicitly. 69 70 USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
+2 -1
arch/um/drivers/chan_user.c
··· 256 256 goto out_close; 257 257 } 258 258 259 - if (os_set_fd_block(*fd_out, 0)) { 259 + err = os_set_fd_block(*fd_out, 0); 260 + if (err) { 260 261 printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " 261 262 "non-blocking.\n"); 262 263 goto out_close;
+2 -1
arch/um/drivers/slip_user.c
··· 145 145 } 146 146 sfd = err; 147 147 148 - if (set_up_tty(sfd)) 148 + err = set_up_tty(sfd); 149 + if (err) 149 150 goto out_close2; 150 151 151 152 pri->slave = sfd;
+1 -2
arch/um/drivers/ubd_kern.c
··· 1242 1242 * enough. So use anyway the io thread. */ 1243 1243 } 1244 1244 stack = alloc_stack(0, 0); 1245 - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 1246 - &thread_fd); 1245 + io_pid = start_io_thread(stack + PAGE_SIZE, &thread_fd); 1247 1246 if(io_pid < 0){ 1248 1247 printk(KERN_ERR 1249 1248 "ubd : Failed to start I/O thread (errno = %d) - "
+895
arch/um/drivers/virt-pci.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + #include <linux/module.h> 7 + #include <linux/pci.h> 8 + #include <linux/virtio.h> 9 + #include <linux/virtio_config.h> 10 + #include <linux/logic_iomem.h> 11 + #include <linux/irqdomain.h> 12 + #include <linux/virtio_pcidev.h> 13 + #include <linux/virtio-uml.h> 14 + #include <linux/delay.h> 15 + #include <linux/msi.h> 16 + #include <asm/unaligned.h> 17 + #include <irq_kern.h> 18 + 19 + #define MAX_DEVICES 8 20 + #define MAX_MSI_VECTORS 32 21 + #define CFG_SPACE_SIZE 4096 22 + 23 + /* for MSI-X we have a 32-bit payload */ 24 + #define MAX_IRQ_MSG_SIZE (sizeof(struct virtio_pcidev_msg) + sizeof(u32)) 25 + #define NUM_IRQ_MSGS 10 26 + 27 + #define HANDLE_NO_FREE(ptr) ((void *)((unsigned long)(ptr) | 1)) 28 + #define HANDLE_IS_NO_FREE(ptr) ((unsigned long)(ptr) & 1) 29 + 30 + struct um_pci_device { 31 + struct virtio_device *vdev; 32 + 33 + /* for now just standard BARs */ 34 + u8 resptr[PCI_STD_NUM_BARS]; 35 + 36 + struct virtqueue *cmd_vq, *irq_vq; 37 + 38 + #define UM_PCI_STAT_WAITING 0 39 + unsigned long status; 40 + 41 + int irq; 42 + }; 43 + 44 + struct um_pci_device_reg { 45 + struct um_pci_device *dev; 46 + void __iomem *iomem; 47 + }; 48 + 49 + static struct pci_host_bridge *bridge; 50 + static DEFINE_MUTEX(um_pci_mtx); 51 + static struct um_pci_device_reg um_pci_devices[MAX_DEVICES]; 52 + static struct fwnode_handle *um_pci_fwnode; 53 + static struct irq_domain *um_pci_inner_domain; 54 + static struct irq_domain *um_pci_msi_domain; 55 + static unsigned long um_pci_msi_used[BITS_TO_LONGS(MAX_MSI_VECTORS)]; 56 + 57 + #define UM_VIRT_PCI_MAXDELAY 40000 58 + 59 + static int um_pci_send_cmd(struct um_pci_device *dev, 60 + struct virtio_pcidev_msg *cmd, 61 + unsigned int cmd_size, 62 + const void *extra, unsigned int extra_size, 63 + void *out, unsigned int out_size) 64 + { 65 + struct scatterlist out_sg, extra_sg, in_sg; 66 + struct scatterlist *sgs_list[] = { 67 + [0] = &out_sg, 68 + [1] = extra ? &extra_sg : &in_sg, 69 + [2] = extra ? &in_sg : NULL, 70 + }; 71 + int delay_count = 0; 72 + int ret, len; 73 + bool posted; 74 + 75 + if (WARN_ON(cmd_size < sizeof(*cmd))) 76 + return -EINVAL; 77 + 78 + switch (cmd->op) { 79 + case VIRTIO_PCIDEV_OP_CFG_WRITE: 80 + case VIRTIO_PCIDEV_OP_MMIO_WRITE: 81 + case VIRTIO_PCIDEV_OP_MMIO_MEMSET: 82 + /* in PCI, writes are posted, so don't wait */ 83 + posted = !out; 84 + WARN_ON(!posted); 85 + break; 86 + default: 87 + posted = false; 88 + break; 89 + } 90 + 91 + if (posted) { 92 + u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC); 93 + 94 + if (ncmd) { 95 + memcpy(ncmd, cmd, cmd_size); 96 + if (extra) 97 + memcpy(ncmd + cmd_size, extra, extra_size); 98 + cmd = (void *)ncmd; 99 + cmd_size += extra_size; 100 + extra = NULL; 101 + extra_size = 0; 102 + } else { 103 + /* try without allocating memory */ 104 + posted = false; 105 + } 106 + } 107 + 108 + sg_init_one(&out_sg, cmd, cmd_size); 109 + if (extra) 110 + sg_init_one(&extra_sg, extra, extra_size); 111 + if (out) 112 + sg_init_one(&in_sg, out, out_size); 113 + 114 + /* add to internal virtio queue */ 115 + ret = virtqueue_add_sgs(dev->cmd_vq, sgs_list, 116 + extra ? 2 : 1, 117 + out ? 1 : 0, 118 + posted ? cmd : HANDLE_NO_FREE(cmd), 119 + GFP_ATOMIC); 120 + if (ret) 121 + return ret; 122 + 123 + if (posted) { 124 + virtqueue_kick(dev->cmd_vq); 125 + return 0; 126 + } 127 + 128 + /* kick and poll for getting a response on the queue */ 129 + set_bit(UM_PCI_STAT_WAITING, &dev->status); 130 + virtqueue_kick(dev->cmd_vq); 131 + 132 + while (1) { 133 + void *completed = virtqueue_get_buf(dev->cmd_vq, &len); 134 + 135 + if (completed == HANDLE_NO_FREE(cmd)) 136 + break; 137 + 138 + if (completed && !HANDLE_IS_NO_FREE(completed)) 139 + kfree(completed); 140 + 141 + if (WARN_ONCE(virtqueue_is_broken(dev->cmd_vq) || 142 + ++delay_count > UM_VIRT_PCI_MAXDELAY, 143 + "um virt-pci delay: %d", delay_count)) { 144 + ret = -EIO; 145 + break; 146 + } 147 + udelay(1); 148 + } 149 + clear_bit(UM_PCI_STAT_WAITING, &dev->status); 150 + 151 + return ret; 152 + } 153 + 154 + static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset, 155 + int size) 156 + { 157 + struct um_pci_device_reg *reg = priv; 158 + struct um_pci_device *dev = reg->dev; 159 + struct virtio_pcidev_msg hdr = { 160 + .op = VIRTIO_PCIDEV_OP_CFG_READ, 161 + .size = size, 162 + .addr = offset, 163 + }; 164 + /* maximum size - we may only use parts of it */ 165 + u8 data[8]; 166 + 167 + if (!dev) 168 + return ~0ULL; 169 + 170 + memset(data, 0xff, sizeof(data)); 171 + 172 + switch (size) { 173 + case 1: 174 + case 2: 175 + case 4: 176 + #ifdef CONFIG_64BIT 177 + case 8: 178 + #endif 179 + break; 180 + default: 181 + WARN(1, "invalid config space read size %d\n", size); 182 + return ~0ULL; 183 + } 184 + 185 + if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, 186 + data, sizeof(data))) 187 + return ~0ULL; 188 + 189 + switch (size) { 190 + case 1: 191 + return data[0]; 192 + case 2: 193 + return le16_to_cpup((void *)data); 194 + case 4: 195 + return le32_to_cpup((void *)data); 196 + #ifdef CONFIG_64BIT 197 + case 8: 198 + return le64_to_cpup((void *)data); 199 + #endif 200 + default: 201 + return ~0ULL; 202 + } 203 + } 204 + 205 + static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size, 206 + unsigned long val) 207 + { 208 + struct um_pci_device_reg *reg = priv; 209 + struct um_pci_device *dev = reg->dev; 210 + struct { 211 + struct virtio_pcidev_msg hdr; 212 + /* maximum size - we may only use parts of it */ 213 + u8 data[8]; 214 + } msg = { 215 + .hdr = { 216 + .op = VIRTIO_PCIDEV_OP_CFG_WRITE, 217 + .size = size, 218 + .addr = offset, 219 + }, 220 + }; 221 + 222 + if (!dev) 223 + return; 224 + 225 + switch (size) { 226 + case 1: 227 + msg.data[0] = (u8)val; 228 + break; 229 + case 2: 230 + put_unaligned_le16(val, (void *)msg.data); 231 + break; 232 + case 4: 233 + put_unaligned_le32(val, (void *)msg.data); 234 + break; 235 + #ifdef CONFIG_64BIT 236 + case 8: 237 + put_unaligned_le64(val, (void *)msg.data); 238 + break; 239 + #endif 240 + default: 241 + WARN(1, "invalid config space write size %d\n", size); 242 + return; 243 + } 244 + 245 + WARN_ON(um_pci_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0)); 246 + } 247 + 248 + static const struct logic_iomem_ops um_pci_device_cfgspace_ops = { 249 + .read = um_pci_cfgspace_read, 250 + .write = um_pci_cfgspace_write, 251 + }; 252 + 253 + static void um_pci_bar_copy_from(void *priv, void *buffer, 254 + unsigned int offset, int size) 255 + { 256 + u8 *resptr = priv; 257 + struct um_pci_device *dev = container_of(resptr - *resptr, 258 + struct um_pci_device, 259 + resptr[0]); 260 + struct virtio_pcidev_msg hdr = { 261 + .op = VIRTIO_PCIDEV_OP_MMIO_READ, 262 + .bar = *resptr, 263 + .size = size, 264 + .addr = offset, 265 + }; 266 + 267 + memset(buffer, 0xff, size); 268 + 269 + um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, buffer, size); 270 + } 271 + 272 + static unsigned long um_pci_bar_read(void *priv, unsigned int offset, 273 + int size) 274 + { 275 + /* maximum size - we may only use parts of it */ 276 + u8 data[8]; 277 + 278 + switch (size) { 279 + case 1: 280 + case 2: 281 + case 4: 282 + #ifdef CONFIG_64BIT 283 + case 8: 284 + #endif 285 + break; 286 + default: 287 + WARN(1, "invalid config space read size %d\n", size); 288 + return ~0ULL; 289 + } 290 + 291 + um_pci_bar_copy_from(priv, data, offset, size); 292 + 293 + switch (size) { 294 + case 1: 295 + return data[0]; 296 + case 2: 297 + return le16_to_cpup((void *)data); 298 + case 4: 299 + return le32_to_cpup((void *)data); 300 + #ifdef CONFIG_64BIT 301 + case 8: 302 + return le64_to_cpup((void *)data); 303 + #endif 304 + default: 305 + return ~0ULL; 306 + } 307 + } 308 + 309 + static void um_pci_bar_copy_to(void *priv, unsigned int offset, 310 + const void *buffer, int size) 311 + { 312 + u8 *resptr = priv; 313 + struct um_pci_device *dev = container_of(resptr - *resptr, 314 + struct um_pci_device, 315 + resptr[0]); 316 + struct virtio_pcidev_msg hdr = { 317 + .op = VIRTIO_PCIDEV_OP_MMIO_WRITE, 318 + .bar = *resptr, 319 + .size = size, 320 + .addr = offset, 321 + }; 322 + 323 + um_pci_send_cmd(dev, &hdr, sizeof(hdr), buffer, size, NULL, 0); 324 + } 325 + 326 + static void um_pci_bar_write(void *priv, unsigned int offset, int size, 327 + unsigned long val) 328 + { 329 + /* maximum size - we may only use parts of it */ 330 + u8 data[8]; 331 + 332 + switch (size) { 333 + case 1: 334 + data[0] = (u8)val; 335 + break; 336 + case 2: 337 + put_unaligned_le16(val, (void *)data); 338 + break; 339 + case 4: 340 + put_unaligned_le32(val, (void *)data); 341 + break; 342 + #ifdef CONFIG_64BIT 343 + case 8: 344 + put_unaligned_le64(val, (void *)data); 345 + break; 346 + #endif 347 + default: 348 + WARN(1, "invalid config space write size %d\n", size); 349 + return; 350 + } 351 + 352 + um_pci_bar_copy_to(priv, offset, data, size); 353 + } 354 + 355 + static void um_pci_bar_set(void *priv, unsigned int offset, u8 value, int size) 356 + { 357 + u8 *resptr = priv; 358 + struct um_pci_device *dev = container_of(resptr - *resptr, 359 + struct um_pci_device, 360 + resptr[0]); 361 + struct { 362 + struct virtio_pcidev_msg hdr; 363 + u8 data; 364 + } msg = { 365 + .hdr = { 366 + .op = VIRTIO_PCIDEV_OP_CFG_WRITE, 367 + .bar = *resptr, 368 + .size = size, 369 + .addr = offset, 370 + }, 371 + .data = value, 372 + }; 373 + 374 + um_pci_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0); 375 + } 376 + 377 + static const struct logic_iomem_ops um_pci_device_bar_ops = { 378 + .read = um_pci_bar_read, 379 + .write = um_pci_bar_write, 380 + .set = um_pci_bar_set, 381 + .copy_from = um_pci_bar_copy_from, 382 + .copy_to = um_pci_bar_copy_to, 383 + }; 384 + 385 + static void __iomem *um_pci_map_bus(struct pci_bus *bus, unsigned int devfn, 386 + int where) 387 + { 388 + struct um_pci_device_reg *dev; 389 + unsigned int busn = bus->number; 390 + 391 + if (busn > 0) 392 + return NULL; 393 + 394 + /* not allowing functions for now ... */ 395 + if (devfn % 8) 396 + return NULL; 397 + 398 + if (devfn / 8 >= ARRAY_SIZE(um_pci_devices)) 399 + return NULL; 400 + 401 + dev = &um_pci_devices[devfn / 8]; 402 + if (!dev) 403 + return NULL; 404 + 405 + return (void __iomem *)((unsigned long)dev->iomem + where); 406 + } 407 + 408 + static struct pci_ops um_pci_ops = { 409 + .map_bus = um_pci_map_bus, 410 + .read = pci_generic_config_read, 411 + .write = pci_generic_config_write, 412 + }; 413 + 414 + static void um_pci_rescan(void) 415 + { 416 + pci_lock_rescan_remove(); 417 + pci_rescan_bus(bridge->bus); 418 + pci_unlock_rescan_remove(); 419 + } 420 + 421 + static void um_pci_irq_vq_addbuf(struct virtqueue *vq, void *buf, bool kick) 422 + { 423 + struct scatterlist sg[1]; 424 + 425 + sg_init_one(sg, buf, MAX_IRQ_MSG_SIZE); 426 + if (virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC)) 427 + kfree(buf); 428 + else if (kick) 429 + virtqueue_kick(vq); 430 + } 431 + 432 + static void um_pci_handle_irq_message(struct virtqueue *vq, 433 + struct virtio_pcidev_msg *msg) 434 + { 435 + struct virtio_device *vdev = vq->vdev; 436 + struct um_pci_device *dev = vdev->priv; 437 + 438 + /* we should properly chain interrupts, but on ARCH=um we don't care */ 439 + 440 + switch (msg->op) { 441 + case VIRTIO_PCIDEV_OP_INT: 442 + generic_handle_irq(dev->irq); 443 + break; 444 + case VIRTIO_PCIDEV_OP_MSI: 445 + /* our MSI message is just the interrupt number */ 446 + if (msg->size == sizeof(u32)) 447 + generic_handle_irq(le32_to_cpup((void *)msg->data)); 448 + else 449 + generic_handle_irq(le16_to_cpup((void *)msg->data)); 450 + break; 451 + case VIRTIO_PCIDEV_OP_PME: 452 + /* nothing to do - we already woke up due to the message */ 453 + break; 454 + default: 455 + dev_err(&vdev->dev, "unexpected virt-pci message %d\n", msg->op); 456 + break; 457 + } 458 + } 459 + 460 + static void um_pci_cmd_vq_cb(struct virtqueue *vq) 461 + { 462 + struct virtio_device *vdev = vq->vdev; 463 + struct um_pci_device *dev = vdev->priv; 464 + void *cmd; 465 + int len; 466 + 467 + if (test_bit(UM_PCI_STAT_WAITING, &dev->status)) 468 + return; 469 + 470 + while ((cmd = virtqueue_get_buf(vq, &len))) { 471 + if (WARN_ON(HANDLE_IS_NO_FREE(cmd))) 472 + continue; 473 + kfree(cmd); 474 + } 475 + } 476 + 477 + static void um_pci_irq_vq_cb(struct virtqueue *vq) 478 + { 479 + struct virtio_pcidev_msg *msg; 480 + int len; 481 + 482 + while ((msg = virtqueue_get_buf(vq, &len))) { 483 + if (len >= sizeof(*msg)) 484 + um_pci_handle_irq_message(vq, msg); 485 + 486 + /* recycle the message buffer */ 487 + um_pci_irq_vq_addbuf(vq, msg, true); 488 + } 489 + } 490 + 491 + static int um_pci_init_vqs(struct um_pci_device *dev) 492 + { 493 + struct virtqueue *vqs[2]; 494 + static const char *const names[2] = { "cmd", "irq" }; 495 + vq_callback_t *cbs[2] = { um_pci_cmd_vq_cb, um_pci_irq_vq_cb }; 496 + int err, i; 497 + 498 + err = virtio_find_vqs(dev->vdev, 2, vqs, cbs, names, NULL); 499 + if (err) 500 + return err; 501 + 502 + dev->cmd_vq = vqs[0]; 503 + dev->irq_vq = vqs[1]; 504 + 505 + for (i = 0; i < NUM_IRQ_MSGS; i++) { 506 + void *msg = kzalloc(MAX_IRQ_MSG_SIZE, GFP_KERNEL); 507 + 508 + if (msg) 509 + um_pci_irq_vq_addbuf(dev->irq_vq, msg, false); 510 + } 511 + 512 + virtqueue_kick(dev->irq_vq); 513 + 514 + return 0; 515 + } 516 + 517 + static int um_pci_virtio_probe(struct virtio_device *vdev) 518 + { 519 + struct um_pci_device *dev; 520 + int i, free = -1; 521 + int err = -ENOSPC; 522 + 523 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 524 + if (!dev) 525 + return -ENOMEM; 526 + 527 + dev->vdev = vdev; 528 + vdev->priv = dev; 529 + 530 + mutex_lock(&um_pci_mtx); 531 + for (i = 0; i < MAX_DEVICES; i++) { 532 + if (um_pci_devices[i].dev) 533 + continue; 534 + free = i; 535 + break; 536 + } 537 + 538 + if (free < 0) 539 + goto error; 540 + 541 + err = um_pci_init_vqs(dev); 542 + if (err) 543 + goto error; 544 + 545 + dev->irq = irq_alloc_desc(numa_node_id()); 546 + if (dev->irq < 0) { 547 + err = dev->irq; 548 + goto error; 549 + } 550 + um_pci_devices[free].dev = dev; 551 + vdev->priv = dev; 552 + 553 + mutex_unlock(&um_pci_mtx); 554 + 555 + device_set_wakeup_enable(&vdev->dev, true); 556 + 557 + /* 558 + * In order to do suspend-resume properly, don't allow VQs 559 + * to be suspended. 560 + */ 561 + virtio_uml_set_no_vq_suspend(vdev, true); 562 + 563 + um_pci_rescan(); 564 + return 0; 565 + error: 566 + mutex_unlock(&um_pci_mtx); 567 + kfree(dev); 568 + return err; 569 + } 570 + 571 + static void um_pci_virtio_remove(struct virtio_device *vdev) 572 + { 573 + struct um_pci_device *dev = vdev->priv; 574 + int i; 575 + 576 + /* Stop all virtqueues */ 577 + vdev->config->reset(vdev); 578 + vdev->config->del_vqs(vdev); 579 + 580 + device_set_wakeup_enable(&vdev->dev, false); 581 + 582 + mutex_lock(&um_pci_mtx); 583 + for (i = 0; i < MAX_DEVICES; i++) { 584 + if (um_pci_devices[i].dev != dev) 585 + continue; 586 + um_pci_devices[i].dev = NULL; 587 + irq_free_desc(dev->irq); 588 + } 589 + mutex_unlock(&um_pci_mtx); 590 + 591 + um_pci_rescan(); 592 + 593 + kfree(dev); 594 + } 595 + 596 + static struct virtio_device_id id_table[] = { 597 + { CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID, VIRTIO_DEV_ANY_ID }, 598 + { 0 }, 599 + }; 600 + MODULE_DEVICE_TABLE(virtio, id_table); 601 + 602 + static struct virtio_driver um_pci_virtio_driver = { 603 + .driver.name = "virtio-pci", 604 + .driver.owner = THIS_MODULE, 605 + .id_table = id_table, 606 + .probe = um_pci_virtio_probe, 607 + .remove = um_pci_virtio_remove, 608 + }; 609 + 610 + static struct resource virt_cfgspace_resource = { 611 + .name = "PCI config space", 612 + .start = 0xf0000000 - MAX_DEVICES * CFG_SPACE_SIZE, 613 + .end = 0xf0000000 - 1, 614 + .flags = IORESOURCE_MEM, 615 + }; 616 + 617 + static long um_pci_map_cfgspace(unsigned long offset, size_t size, 618 + const struct logic_iomem_ops **ops, 619 + void **priv) 620 + { 621 + if (WARN_ON(size > CFG_SPACE_SIZE || offset % CFG_SPACE_SIZE)) 622 + return -EINVAL; 623 + 624 + if (offset / CFG_SPACE_SIZE < MAX_DEVICES) { 625 + *ops = &um_pci_device_cfgspace_ops; 626 + *priv = &um_pci_devices[offset / CFG_SPACE_SIZE]; 627 + return 0; 628 + } 629 + 630 + WARN(1, "cannot map offset 0x%lx/0x%zx\n", offset, size); 631 + return -ENOENT; 632 + } 633 + 634 + static const struct logic_iomem_region_ops um_pci_cfgspace_ops = { 635 + .map = um_pci_map_cfgspace, 636 + }; 637 + 638 + static struct resource virt_iomem_resource = { 639 + .name = "PCI iomem", 640 + .start = 0xf0000000, 641 + .end = 0xffffffff, 642 + .flags = IORESOURCE_MEM, 643 + }; 644 + 645 + struct um_pci_map_iomem_data { 646 + unsigned long offset; 647 + size_t size; 648 + const struct logic_iomem_ops **ops; 649 + void **priv; 650 + long ret; 651 + }; 652 + 653 + static int um_pci_map_iomem_walk(struct pci_dev *pdev, void *_data) 654 + { 655 + struct um_pci_map_iomem_data *data = _data; 656 + struct um_pci_device_reg *reg = &um_pci_devices[pdev->devfn / 8]; 657 + struct um_pci_device *dev; 658 + int i; 659 + 660 + if (!reg->dev) 661 + return 0; 662 + 663 + for (i = 0; i < ARRAY_SIZE(dev->resptr); i++) { 664 + struct resource *r = &pdev->resource[i]; 665 + 666 + if ((r->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) 667 + continue; 668 + 669 + /* 670 + * must be the whole or part of the resource, 671 + * not allowed to only overlap 672 + */ 673 + if (data->offset < r->start || data->offset > r->end) 674 + continue; 675 + if (data->offset + data->size - 1 > r->end) 676 + continue; 677 + 678 + dev = reg->dev; 679 + *data->ops = &um_pci_device_bar_ops; 680 + dev->resptr[i] = i; 681 + *data->priv = &dev->resptr[i]; 682 + data->ret = data->offset - r->start; 683 + 684 + /* no need to continue */ 685 + return 1; 686 + } 687 + 688 + return 0; 689 + } 690 + 691 + static long um_pci_map_iomem(unsigned long offset, size_t size, 692 + const struct logic_iomem_ops **ops, 693 + void **priv) 694 + { 695 + struct um_pci_map_iomem_data data = { 696 + /* we want the full address here */ 697 + .offset = offset + virt_iomem_resource.start, 698 + .size = size, 699 + .ops = ops, 700 + .priv = priv, 701 + .ret = -ENOENT, 702 + }; 703 + 704 + pci_walk_bus(bridge->bus, um_pci_map_iomem_walk, &data); 705 + return data.ret; 706 + } 707 + 708 + static const struct logic_iomem_region_ops um_pci_iomem_ops = { 709 + .map = um_pci_map_iomem, 710 + }; 711 + 712 + static void um_pci_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 713 + { 714 + /* 715 + * This is a very low address and not actually valid 'physical' memory 716 + * in UML, so we can simply map MSI(-X) vectors to there, it cannot be 717 + * legitimately written to by the device in any other way. 718 + * We use the (virtual) IRQ number here as the message to simplify the 719 + * code that receives the message, where for now we simply trust the 720 + * device to send the correct message. 721 + */ 722 + msg->address_hi = 0; 723 + msg->address_lo = 0xa0000; 724 + msg->data = data->irq; 725 + } 726 + 727 + static struct irq_chip um_pci_msi_bottom_irq_chip = { 728 + .name = "UM virtio MSI", 729 + .irq_compose_msi_msg = um_pci_compose_msi_msg, 730 + }; 731 + 732 + static int um_pci_inner_domain_alloc(struct irq_domain *domain, 733 + unsigned int virq, unsigned int nr_irqs, 734 + void *args) 735 + { 736 + unsigned long bit; 737 + 738 + WARN_ON(nr_irqs != 1); 739 + 740 + mutex_lock(&um_pci_mtx); 741 + bit = find_first_zero_bit(um_pci_msi_used, MAX_MSI_VECTORS); 742 + if (bit >= MAX_MSI_VECTORS) { 743 + mutex_unlock(&um_pci_mtx); 744 + return -ENOSPC; 745 + } 746 + 747 + set_bit(bit, um_pci_msi_used); 748 + mutex_unlock(&um_pci_mtx); 749 + 750 + irq_domain_set_info(domain, virq, bit, &um_pci_msi_bottom_irq_chip, 751 + domain->host_data, handle_simple_irq, 752 + NULL, NULL); 753 + 754 + return 0; 755 + } 756 + 757 + static void um_pci_inner_domain_free(struct irq_domain *domain, 758 + unsigned int virq, unsigned int nr_irqs) 759 + { 760 + struct irq_data *d = irq_domain_get_irq_data(domain, virq); 761 + 762 + mutex_lock(&um_pci_mtx); 763 + 764 + if (!test_bit(d->hwirq, um_pci_msi_used)) 765 + pr_err("trying to free unused MSI#%lu\n", d->hwirq); 766 + else 767 + __clear_bit(d->hwirq, um_pci_msi_used); 768 + 769 + mutex_unlock(&um_pci_mtx); 770 + } 771 + 772 + static const struct irq_domain_ops um_pci_inner_domain_ops = { 773 + .alloc = um_pci_inner_domain_alloc, 774 + .free = um_pci_inner_domain_free, 775 + }; 776 + 777 + static struct irq_chip um_pci_msi_irq_chip = { 778 + .name = "UM virtio PCIe MSI", 779 + .irq_mask = pci_msi_mask_irq, 780 + .irq_unmask = pci_msi_unmask_irq, 781 + }; 782 + 783 + static struct msi_domain_info um_pci_msi_domain_info = { 784 + .flags = MSI_FLAG_USE_DEF_DOM_OPS | 785 + MSI_FLAG_USE_DEF_CHIP_OPS | 786 + MSI_FLAG_PCI_MSIX, 787 + .chip = &um_pci_msi_irq_chip, 788 + }; 789 + 790 + static struct resource busn_resource = { 791 + .name = "PCI busn", 792 + .start = 0, 793 + .end = 0, 794 + .flags = IORESOURCE_BUS, 795 + }; 796 + 797 + static int um_pci_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) 798 + { 799 + struct um_pci_device_reg *reg = &um_pci_devices[pdev->devfn / 8]; 800 + 801 + if (WARN_ON(!reg->dev)) 802 + return -EINVAL; 803 + 804 + /* Yes, we map all pins to the same IRQ ... doesn't matter for now. */ 805 + return reg->dev->irq; 806 + } 807 + 808 + void *pci_root_bus_fwnode(struct pci_bus *bus) 809 + { 810 + return um_pci_fwnode; 811 + } 812 + 813 + int um_pci_init(void) 814 + { 815 + int err, i; 816 + 817 + WARN_ON(logic_iomem_add_region(&virt_cfgspace_resource, 818 + &um_pci_cfgspace_ops)); 819 + WARN_ON(logic_iomem_add_region(&virt_iomem_resource, 820 + &um_pci_iomem_ops)); 821 + 822 + if (WARN(CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID < 0, 823 + "No virtio device ID configured for PCI - no PCI support\n")) 824 + return 0; 825 + 826 + bridge = pci_alloc_host_bridge(0); 827 + if (!bridge) 828 + return -ENOMEM; 829 + 830 + um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci"); 831 + if (!um_pci_fwnode) { 832 + err = -ENOMEM; 833 + goto free; 834 + } 835 + 836 + um_pci_inner_domain = __irq_domain_add(um_pci_fwnode, MAX_MSI_VECTORS, 837 + MAX_MSI_VECTORS, 0, 838 + &um_pci_inner_domain_ops, NULL); 839 + if (!um_pci_inner_domain) { 840 + err = -ENOMEM; 841 + goto free; 842 + } 843 + 844 + um_pci_msi_domain = pci_msi_create_irq_domain(um_pci_fwnode, 845 + &um_pci_msi_domain_info, 846 + um_pci_inner_domain); 847 + if (!um_pci_msi_domain) { 848 + err = -ENOMEM; 849 + goto free; 850 + } 851 + 852 + pci_add_resource(&bridge->windows, &virt_iomem_resource); 853 + pci_add_resource(&bridge->windows, &busn_resource); 854 + bridge->ops = &um_pci_ops; 855 + bridge->map_irq = um_pci_map_irq; 856 + 857 + for (i = 0; i < MAX_DEVICES; i++) { 858 + resource_size_t start; 859 + 860 + start = virt_cfgspace_resource.start + i * CFG_SPACE_SIZE; 861 + um_pci_devices[i].iomem = ioremap(start, CFG_SPACE_SIZE); 862 + if (WARN(!um_pci_devices[i].iomem, "failed to map %d\n", i)) { 863 + err = -ENOMEM; 864 + goto free; 865 + } 866 + } 867 + 868 + err = pci_host_probe(bridge); 869 + if (err) 870 + goto free; 871 + 872 + err = register_virtio_driver(&um_pci_virtio_driver); 873 + if (err) 874 + goto free; 875 + return 0; 876 + free: 877 + if (um_pci_inner_domain) 878 + irq_domain_remove(um_pci_inner_domain); 879 + if (um_pci_fwnode) 880 + irq_domain_free_fwnode(um_pci_fwnode); 881 + pci_free_resource_list(&bridge->windows); 882 + pci_free_host_bridge(bridge); 883 + return err; 884 + } 885 + module_init(um_pci_init); 886 + 887 + void um_pci_exit(void) 888 + { 889 + unregister_virtio_driver(&um_pci_virtio_driver); 890 + irq_domain_remove(um_pci_msi_domain); 891 + irq_domain_remove(um_pci_inner_domain); 892 + pci_free_resource_list(&bridge->windows); 893 + pci_free_host_bridge(bridge); 894 + } 895 + module_exit(um_pci_exit);
+30 -10
arch/um/drivers/virtio_uml.c
··· 56 56 u8 status; 57 57 u8 registered:1; 58 58 u8 suspended:1; 59 + u8 no_vq_suspend:1; 59 60 60 61 u8 config_changed_irq:1; 61 62 uint64_t vq_irq_vq_map; ··· 1099 1098 kfree(vu_dev); 1100 1099 } 1101 1100 1101 + void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, 1102 + bool no_vq_suspend) 1103 + { 1104 + struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); 1105 + 1106 + if (WARN_ON(vdev->config != &virtio_uml_config_ops)) 1107 + return; 1108 + 1109 + vu_dev->no_vq_suspend = no_vq_suspend; 1110 + dev_info(&vdev->dev, "%sabled VQ suspend\n", 1111 + no_vq_suspend ? "dis" : "en"); 1112 + } 1113 + 1102 1114 /* Platform device */ 1103 1115 1104 1116 static int virtio_uml_probe(struct platform_device *pdev) ··· 1316 1302 static int virtio_uml_suspend(struct platform_device *pdev, pm_message_t state) 1317 1303 { 1318 1304 struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); 1319 - struct virtqueue *vq; 1320 1305 1321 - virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1322 - struct virtio_uml_vq_info *info = vq->priv; 1306 + if (!vu_dev->no_vq_suspend) { 1307 + struct virtqueue *vq; 1323 1308 1324 - info->suspended = true; 1325 - vhost_user_set_vring_enable(vu_dev, vq->index, false); 1309 + virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1310 + struct virtio_uml_vq_info *info = vq->priv; 1311 + 1312 + info->suspended = true; 1313 + vhost_user_set_vring_enable(vu_dev, vq->index, false); 1314 + } 1326 1315 } 1327 1316 1328 1317 if (!device_may_wakeup(&vu_dev->vdev.dev)) { ··· 1339 1322 static int virtio_uml_resume(struct platform_device *pdev) 1340 1323 { 1341 1324 struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); 1342 - struct virtqueue *vq; 1343 1325 1344 - virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1345 - struct virtio_uml_vq_info *info = vq->priv; 1326 + if (!vu_dev->no_vq_suspend) { 1327 + struct virtqueue *vq; 1346 1328 1347 - info->suspended = false; 1348 - vhost_user_set_vring_enable(vu_dev, vq->index, true); 1329 + virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1330 + struct virtio_uml_vq_info *info = vq->priv; 1331 + 1332 + info->suspended = false; 1333 + vhost_user_set_vring_enable(vu_dev, vq->index, true); 1334 + } 1349 1335 } 1350 1336 1351 1337 vu_dev->suspended = false;
+2 -2
arch/um/include/asm/Kbuild
··· 7 7 generic-y += emergency-restart.h 8 8 generic-y += exec.h 9 9 generic-y += extable.h 10 + generic-y += fb.h 10 11 generic-y += ftrace.h 11 - generic-y += futex.h 12 12 generic-y += hw_irq.h 13 13 generic-y += irq_regs.h 14 14 generic-y += irq_work.h ··· 17 17 generic-y += mmiowb.h 18 18 generic-y += module.lds.h 19 19 generic-y += param.h 20 - generic-y += pci.h 21 20 generic-y += percpu.h 22 21 generic-y += preempt.h 23 22 generic-y += softirq_stack.h ··· 26 27 generic-y += word-at-a-time.h 27 28 generic-y += kprobes.h 28 29 generic-y += mm_hooks.h 30 + generic-y += vga.h
+9
arch/um/include/asm/cacheflush.h
··· 1 + #ifndef __UM_ASM_CACHEFLUSH_H 2 + #define __UM_ASM_CACHEFLUSH_H 3 + 4 + #include <asm/tlbflush.h> 5 + #define flush_cache_vmap flush_tlb_kernel_range 6 + #define flush_cache_vunmap flush_tlb_kernel_range 7 + 8 + #include <asm-generic/cacheflush.h> 9 + #endif /* __UM_ASM_CACHEFLUSH_H */
+157
arch/um/include/asm/cpufeature.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_UM_CPUFEATURE_H 3 + #define _ASM_UM_CPUFEATURE_H 4 + 5 + #include <asm/processor.h> 6 + 7 + #if defined(__KERNEL__) && !defined(__ASSEMBLY__) 8 + 9 + #include <asm/asm.h> 10 + #include <linux/bitops.h> 11 + 12 + extern const char * const x86_cap_flags[NCAPINTS*32]; 13 + extern const char * const x86_power_flags[32]; 14 + #define X86_CAP_FMT "%s" 15 + #define x86_cap_flag(flag) x86_cap_flags[flag] 16 + 17 + /* 18 + * In order to save room, we index into this array by doing 19 + * X86_BUG_<name> - NCAPINTS*32. 20 + */ 21 + extern const char * const x86_bug_flags[NBUGINTS*32]; 22 + 23 + #define test_cpu_cap(c, bit) \ 24 + test_bit(bit, (unsigned long *)((c)->x86_capability)) 25 + 26 + /* 27 + * There are 32 bits/features in each mask word. The high bits 28 + * (selected with (bit>>5) give us the word number and the low 5 29 + * bits give us the bit/feature number inside the word. 30 + * (1UL<<((bit)&31) gives us a mask for the feature_bit so we can 31 + * see if it is set in the mask word. 32 + */ 33 + #define CHECK_BIT_IN_MASK_WORD(maskname, word, bit) \ 34 + (((bit)>>5)==(word) && (1UL<<((bit)&31) & maskname##word )) 35 + 36 + #define cpu_has(c, bit) \ 37 + test_cpu_cap(c, bit) 38 + 39 + #define this_cpu_has(bit) \ 40 + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ 41 + x86_this_cpu_test_bit(bit, \ 42 + (unsigned long __percpu *)&cpu_info.x86_capability)) 43 + 44 + /* 45 + * This macro is for detection of features which need kernel 46 + * infrastructure to be used. It may *not* directly test the CPU 47 + * itself. Use the cpu_has() family if you want true runtime 48 + * testing of CPU features, like in hypervisor code where you are 49 + * supporting a possible guest feature where host support for it 50 + * is not relevant. 51 + */ 52 + #define cpu_feature_enabled(bit) \ 53 + (__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit)) 54 + 55 + #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) 56 + 57 + #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) 58 + 59 + extern void setup_clear_cpu_cap(unsigned int bit); 60 + 61 + #define setup_force_cpu_cap(bit) do { \ 62 + set_cpu_cap(&boot_cpu_data, bit); \ 63 + set_bit(bit, (unsigned long *)cpu_caps_set); \ 64 + } while (0) 65 + 66 + #define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit) 67 + 68 + #if defined(__clang__) && !defined(CONFIG_CC_HAS_ASM_GOTO) 69 + 70 + /* 71 + * Workaround for the sake of BPF compilation which utilizes kernel 72 + * headers, but clang does not support ASM GOTO and fails the build. 73 + */ 74 + #ifndef __BPF_TRACING__ 75 + #warning "Compiler lacks ASM_GOTO support. Add -D __BPF_TRACING__ to your compiler arguments" 76 + #endif 77 + 78 + #define static_cpu_has(bit) boot_cpu_has(bit) 79 + 80 + #else 81 + 82 + /* 83 + * Static testing of CPU features. Used the same as boot_cpu_has(). It 84 + * statically patches the target code for additional performance. Use 85 + * static_cpu_has() only in fast paths, where every cycle counts. Which 86 + * means that the boot_cpu_has() variant is already fast enough for the 87 + * majority of cases and you should stick to using it as it is generally 88 + * only two instructions: a RIP-relative MOV and a TEST. 89 + */ 90 + static __always_inline bool _static_cpu_has(u16 bit) 91 + { 92 + asm_volatile_goto("1: jmp 6f\n" 93 + "2:\n" 94 + ".skip -(((5f-4f) - (2b-1b)) > 0) * " 95 + "((5f-4f) - (2b-1b)),0x90\n" 96 + "3:\n" 97 + ".section .altinstructions,\"a\"\n" 98 + " .long 1b - .\n" /* src offset */ 99 + " .long 4f - .\n" /* repl offset */ 100 + " .word %P[always]\n" /* always replace */ 101 + " .byte 3b - 1b\n" /* src len */ 102 + " .byte 5f - 4f\n" /* repl len */ 103 + " .byte 3b - 2b\n" /* pad len */ 104 + ".previous\n" 105 + ".section .altinstr_replacement,\"ax\"\n" 106 + "4: jmp %l[t_no]\n" 107 + "5:\n" 108 + ".previous\n" 109 + ".section .altinstructions,\"a\"\n" 110 + " .long 1b - .\n" /* src offset */ 111 + " .long 0\n" /* no replacement */ 112 + " .word %P[feature]\n" /* feature bit */ 113 + " .byte 3b - 1b\n" /* src len */ 114 + " .byte 0\n" /* repl len */ 115 + " .byte 0\n" /* pad len */ 116 + ".previous\n" 117 + ".section .altinstr_aux,\"ax\"\n" 118 + "6:\n" 119 + " testb %[bitnum],%[cap_byte]\n" 120 + " jnz %l[t_yes]\n" 121 + " jmp %l[t_no]\n" 122 + ".previous\n" 123 + : : [feature] "i" (bit), 124 + [always] "i" (X86_FEATURE_ALWAYS), 125 + [bitnum] "i" (1 << (bit & 7)), 126 + [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3]) 127 + : : t_yes, t_no); 128 + t_yes: 129 + return true; 130 + t_no: 131 + return false; 132 + } 133 + 134 + #define static_cpu_has(bit) \ 135 + ( \ 136 + __builtin_constant_p(boot_cpu_has(bit)) ? \ 137 + boot_cpu_has(bit) : \ 138 + _static_cpu_has(bit) \ 139 + ) 140 + #endif 141 + 142 + #define cpu_has_bug(c, bit) cpu_has(c, (bit)) 143 + #define set_cpu_bug(c, bit) set_cpu_cap(c, (bit)) 144 + 145 + #define static_cpu_has_bug(bit) static_cpu_has((bit)) 146 + #define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit)) 147 + #define boot_cpu_set_bug(bit) set_cpu_cap(&boot_cpu_data, (bit)) 148 + 149 + #define MAX_CPU_FEATURES (NCAPINTS * 32) 150 + #define cpu_have_feature boot_cpu_has 151 + 152 + #define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X" 153 + #define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \ 154 + boot_cpu_data.x86_model 155 + 156 + #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */ 157 + #endif /* _ASM_UM_CPUFEATURE_H */
+20
arch/um/include/asm/fpu/api.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + #ifndef _ASM_UM_FPU_API_H 3 + #define _ASM_UM_FPU_API_H 4 + 5 + /* Copyright (c) 2020 Cambridge Greys Ltd 6 + * Copyright (c) 2020 Red Hat Inc. 7 + * A set of "dummy" defines to allow the direct inclusion 8 + * of x86 optimized copy, xor, etc routines into the 9 + * UML code tree. */ 10 + 11 + #define kernel_fpu_begin() (void)0 12 + #define kernel_fpu_end() (void)0 13 + 14 + static inline bool irq_fpu_usable(void) 15 + { 16 + return true; 17 + } 18 + 19 + 20 + #endif
+14
arch/um/include/asm/futex.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_UM_FUTEX_H 3 + #define _ASM_UM_FUTEX_H 4 + 5 + #include <linux/futex.h> 6 + #include <linux/uaccess.h> 7 + #include <asm/errno.h> 8 + 9 + 10 + int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr); 11 + int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 12 + u32 oldval, u32 newval); 13 + 14 + #endif
+7
arch/um/include/asm/io.h
··· 3 3 #define _ASM_UM_IO_H 4 4 #include <linux/types.h> 5 5 6 + /* get emulated iomem (if desired) */ 7 + #include <asm-generic/logic_io.h> 8 + 9 + #ifndef ioremap 6 10 #define ioremap ioremap 7 11 static inline void __iomem *ioremap(phys_addr_t offset, size_t size) 8 12 { 9 13 return NULL; 10 14 } 15 + #endif /* ioremap */ 11 16 17 + #ifndef iounmap 12 18 #define iounmap iounmap 13 19 static inline void iounmap(void __iomem *addr) 14 20 { 15 21 } 22 + #endif /* iounmap */ 16 23 17 24 #include <asm-generic/io.h> 18 25
+7 -1
arch/um/include/asm/irq.h
··· 31 31 32 32 #endif 33 33 34 - #define NR_IRQS 64 34 + #define UM_LAST_SIGNAL_IRQ 64 35 + /* If we have (simulated) PCI MSI, allow 64 more interrupt numbers for it */ 36 + #ifdef CONFIG_PCI_MSI 37 + #define NR_IRQS (UM_LAST_SIGNAL_IRQ + 64) 38 + #else 39 + #define NR_IRQS UM_LAST_SIGNAL_IRQ 40 + #endif /* CONFIG_PCI_MSI */ 35 41 36 42 #include <asm-generic/irq.h> 37 43 #endif
+5 -5
arch/um/include/asm/irqflags.h
··· 2 2 #ifndef __UM_IRQFLAGS_H 3 3 #define __UM_IRQFLAGS_H 4 4 5 - extern int get_signals(void); 6 - extern int set_signals(int enable); 7 - extern void block_signals(void); 8 - extern void unblock_signals(void); 5 + extern int signals_enabled; 6 + int set_signals(int enable); 7 + void block_signals(void); 8 + void unblock_signals(void); 9 9 10 10 #define arch_local_save_flags arch_local_save_flags 11 11 static inline unsigned long arch_local_save_flags(void) 12 12 { 13 - return get_signals(); 13 + return signals_enabled; 14 14 } 15 15 16 16 #define arch_local_irq_restore arch_local_irq_restore
+1
arch/um/include/asm/msi.h
··· 1 + #include <asm-generic/msi.h>
+39
arch/um/include/asm/pci.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef __ASM_UM_PCI_H 3 + #define __ASM_UM_PCI_H 4 + #include <linux/types.h> 5 + #include <asm/io.h> 6 + 7 + #define PCIBIOS_MIN_IO 0 8 + #define PCIBIOS_MIN_MEM 0 9 + 10 + #define pcibios_assign_all_busses() 1 11 + 12 + extern int isa_dma_bridge_buggy; 13 + 14 + #ifdef CONFIG_PCI 15 + static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) 16 + { 17 + /* no legacy IRQs */ 18 + return -ENODEV; 19 + } 20 + #endif 21 + 22 + #ifdef CONFIG_PCI_DOMAINS 23 + static inline int pci_proc_domain(struct pci_bus *bus) 24 + { 25 + /* always show the domain in /proc */ 26 + return 1; 27 + } 28 + #endif /* CONFIG_PCI */ 29 + 30 + #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN 31 + /* 32 + * This is a bit of an annoying hack, and it assumes we only have 33 + * the virt-pci (if anything). Which is true, but still. 34 + */ 35 + void *pci_root_bus_fwnode(struct pci_bus *bus); 36 + #define pci_root_bus_fwnode pci_root_bus_fwnode 37 + #endif 38 + 39 + #endif /* __ASM_UM_PCI_H */
+8
arch/um/include/asm/processor-generic.h
··· 16 16 17 17 #include <linux/prefetch.h> 18 18 19 + #include <asm/cpufeatures.h> 20 + 19 21 struct mm_struct; 20 22 21 23 struct thread_struct { ··· 92 90 struct cpuinfo_um { 93 91 unsigned long loops_per_jiffy; 94 92 int ipi_pipe[2]; 93 + int cache_alignment; 94 + union { 95 + __u32 x86_capability[NCAPINTS + NBUGINTS]; 96 + unsigned long x86_capability_alignment; 97 + }; 95 98 }; 96 99 97 100 extern struct cpuinfo_um boot_cpu_data; 98 101 99 102 #define cpu_data (&boot_cpu_data) 100 103 #define current_cpu_data boot_cpu_data 104 + #define cache_line_size() (boot_cpu_data.cache_alignment) 101 105 102 106 #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) 103 107 extern unsigned long get_wchan(struct task_struct *p);
+1 -1
arch/um/include/asm/tlb.h
··· 5 5 #include <linux/mm.h> 6 6 7 7 #include <asm/tlbflush.h> 8 - #include <asm-generic/cacheflush.h> 8 + #include <asm/cacheflush.h> 9 9 #include <asm-generic/tlb.h> 10 10 11 11 #endif
+16 -1
arch/um/include/asm/xor.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <asm-generic/xor.h> 2 + #ifndef _ASM_UM_XOR_H 3 + #define _ASM_UM_XOR_H 4 + 5 + #ifdef CONFIG_64BIT 6 + #undef CONFIG_X86_32 7 + #else 8 + #define CONFIG_X86_32 1 9 + #endif 10 + 11 + #include <asm/cpufeature.h> 12 + #include <../../x86/include/asm/xor.h> 3 13 #include <linux/time-internal.h> 4 14 15 + #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 16 + #undef XOR_SELECT_TEMPLATE 5 17 /* pick an arbitrary one - measuring isn't possible with inf-cpu */ 6 18 #define XOR_SELECT_TEMPLATE(x) \ 7 19 (time_travel_mode == TT_MODE_INFCPU ? &xor_block_8regs : NULL) 20 + #endif 21 + 22 + #endif
+1 -11
arch/um/include/linux/time-internal.h
··· 8 8 #define __TIMER_INTERNAL_H__ 9 9 #include <linux/list.h> 10 10 #include <asm/bug.h> 11 + #include <shared/timetravel.h> 11 12 12 13 #define TIMER_MULTIPLIER 256 13 14 #define TIMER_MIN_DELTA 500 14 - 15 - enum time_travel_mode { 16 - TT_MODE_OFF, 17 - TT_MODE_BASIC, 18 - TT_MODE_INFCPU, 19 - TT_MODE_EXTERNAL, 20 - }; 21 15 22 16 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 23 17 struct time_travel_event { ··· 20 26 struct list_head list; 21 27 bool pending, onstack; 22 28 }; 23 - 24 - extern enum time_travel_mode time_travel_mode; 25 29 26 30 void time_travel_sleep(void); 27 31 ··· 53 61 #else 54 62 struct time_travel_event { 55 63 }; 56 - 57 - #define time_travel_mode TT_MODE_OFF 58 64 59 65 static inline void time_travel_sleep(void) 60 66 {
+13
arch/um/include/linux/virtio-uml.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + 7 + #ifndef __VIRTIO_UML_H__ 8 + #define __VIRTIO_UML_H__ 9 + 10 + void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, 11 + bool no_vq_suspend); 12 + 13 + #endif /* __VIRTIO_UML_H__ */
+1
arch/um/include/shared/irq_user.h
··· 17 17 18 18 struct siginfo; 19 19 extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 20 + void sigio_run_timetravel_handlers(void); 20 21 extern void free_irq_by_fd(int fd); 21 22 extern void deactivate_fd(int fd, int irqnum); 22 23 extern int deactivate_all_fds(void);
-1
arch/um/include/shared/kern_util.h
··· 33 33 int is_write, int is_user, int *code_out); 34 34 35 35 extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); 36 - extern int smp_sigio_handler(void); 37 36 extern void initial_thread_cb(void (*proc)(void *), void *arg); 38 37 extern int is_syscall(unsigned long addr); 39 38
+7 -7
arch/um/include/shared/longjmp.h
··· 5 5 #include <sysdep/archsetjmp.h> 6 6 #include <os.h> 7 7 8 + extern int signals_enabled; 8 9 extern int setjmp(jmp_buf); 9 10 extern void longjmp(jmp_buf, int); 10 11 ··· 13 12 longjmp(*buf, val); \ 14 13 } while(0) 15 14 16 - #define UML_SETJMP(buf) ({ \ 17 - int n; \ 18 - volatile int enable; \ 19 - enable = get_signals(); \ 20 - n = setjmp(*buf); \ 21 - if(n != 0) \ 22 - set_signals_trace(enable); \ 15 + #define UML_SETJMP(buf) ({ \ 16 + int n, enable; \ 17 + enable = *(volatile int *)&signals_enabled; \ 18 + n = setjmp(*buf); \ 19 + if(n != 0) \ 20 + set_signals_trace(enable); \ 23 21 n; }) 24 22 25 23 #endif
+6 -2
arch/um/include/shared/os.h
··· 187 187 extern void os_early_checks(void); 188 188 extern void os_check_bugs(void); 189 189 extern void check_host_supports_tls(int *supports_tls, int *tls_min); 190 + extern void get_host_cpu_features( 191 + void (*flags_helper_func)(char *line), 192 + void (*cache_helper_func)(char *line)); 190 193 191 194 /* mem.c */ 192 195 extern int create_mem_file(unsigned long long len); ··· 214 211 extern int os_unmap_memory(void *addr, int len); 215 212 extern int os_drop_memory(void *addr, int length); 216 213 extern int can_drop_memory(void); 217 - extern void os_flush_stdout(void); 218 214 extern int os_mincore(void *addr, unsigned long len); 219 215 220 216 /* execvp.c */ ··· 239 237 extern int change_sig(int signal, int on); 240 238 extern void block_signals(void); 241 239 extern void unblock_signals(void); 242 - extern int get_signals(void); 243 240 extern int set_signals(int enable); 244 241 extern int set_signals_trace(int enable); 245 242 extern int os_is_signal_stack(void); 246 243 extern void deliver_alarm(void); 247 244 extern void register_pm_wake_signal(void); 245 + extern void block_signals_hard(void); 246 + extern void unblock_signals_hard(void); 247 + extern void mark_sigio_pending(void); 248 248 249 249 /* util.c */ 250 250 extern void stack_protections(unsigned long address);
+22
arch/um/include/shared/timetravel.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2019-2021 Intel Corporation 4 + */ 5 + #ifndef _UM_TIME_TRAVEL_H_ 6 + #define _UM_TIME_TRAVEL_H_ 7 + 8 + enum time_travel_mode { 9 + TT_MODE_OFF, 10 + TT_MODE_BASIC, 11 + TT_MODE_INFCPU, 12 + TT_MODE_EXTERNAL, 13 + }; 14 + 15 + #if defined(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT) || \ 16 + defined(CONFIG_UML_TIME_TRAVEL_SUPPORT) 17 + extern enum time_travel_mode time_travel_mode; 18 + #else 19 + #define time_travel_mode TT_MODE_OFF 20 + #endif /* (UML_)CONFIG_UML_TIME_TRAVEL_SUPPORT */ 21 + 22 + #endif /* _UM_TIME_TRAVEL_H_ */
+12 -2
arch/um/kernel/Makefile
··· 17 17 obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ 18 18 physmem.o process.o ptrace.o reboot.o sigio.o \ 19 19 signal.o syscall.o sysrq.o time.o tlb.o trap.o \ 20 - um_arch.o umid.o maccess.o kmsg_dump.o skas/ 20 + um_arch.o umid.o maccess.o kmsg_dump.o capflags.o skas/ 21 21 22 22 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o 23 23 obj-$(CONFIG_GPROF) += gprof_syms.o 24 24 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 25 25 obj-$(CONFIG_STACKTRACE) += stacktrace.o 26 + obj-$(CONFIG_GENERIC_PCI_IOMAP) += ioport.o 26 27 27 28 USER_OBJS := config.o 28 29 29 30 include arch/um/scripts/Makefile.rules 30 31 31 - targets := config.c config.tmp 32 + targets := config.c config.tmp capflags.c 32 33 33 34 # Be careful with the below Sed code - sed is pitfall-rich! 34 35 # We use sed to lower build requirements, for "embedded" builders for instance. ··· 43 42 44 43 $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE 45 44 $(call if_changed,quote2) 45 + 46 + quiet_cmd_mkcapflags = MKCAP $@ 47 + cmd_mkcapflags = $(CONFIG_SHELL) $(srctree)/$(src)/../../x86/kernel/cpu/mkcapflags.sh $@ $^ 48 + 49 + cpufeature = $(src)/../../x86/include/asm/cpufeatures.h 50 + vmxfeature = $(src)/../../x86/include/asm/vmxfeatures.h 51 + 52 + $(obj)/capflags.c: $(cpufeature) $(vmxfeature) $(src)/../../x86/kernel/cpu/mkcapflags.sh FORCE 53 + $(call if_changed,mkcapflags) 46 54 47 55 quiet_cmd_quote2 = QUOTE $@ 48 56 cmd_quote2 = sed -e '/CONFIG/{' \
+13
arch/um/kernel/ioport.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + #include <asm/iomap.h> 7 + #include <asm-generic/pci_iomap.h> 8 + 9 + void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port, 10 + unsigned int nr) 11 + { 12 + return NULL; 13 + }
+39 -13
arch/um/kernel/irq.c
··· 56 56 57 57 static DEFINE_SPINLOCK(irq_lock); 58 58 static LIST_HEAD(active_fds); 59 - static DECLARE_BITMAP(irqs_allocated, NR_IRQS); 59 + static DECLARE_BITMAP(irqs_allocated, UM_LAST_SIGNAL_IRQ); 60 60 static bool irqs_suspended; 61 61 62 62 static void irq_io_loop(struct irq_reg *irq, struct uml_pt_regs *regs) ··· 101 101 if (!reg->timetravel_handler) 102 102 return false; 103 103 104 - /* prevent nesting - we'll get it again later when we SIGIO ourselves */ 105 - if (reg->pending_on_resume) 106 - return true; 107 - 104 + /* 105 + * Handle all messages - we might get multiple even while 106 + * interrupts are already suspended, due to suspend order 107 + * etc. Note that time_travel_add_irq_event() will not add 108 + * an event twice, if it's pending already "first wins". 109 + */ 108 110 reg->timetravel_handler(reg->irq, entry->fd, reg->id, &reg->event); 109 111 110 112 if (!reg->event.pending) ··· 125 123 #endif 126 124 127 125 static void sigio_reg_handler(int idx, struct irq_entry *entry, enum um_irq_type t, 128 - struct uml_pt_regs *regs) 126 + struct uml_pt_regs *regs, 127 + bool timetravel_handlers_only) 129 128 { 130 129 struct irq_reg *reg = &entry->reg[t]; 131 130 ··· 139 136 if (irq_do_timetravel_handler(entry, t)) 140 137 return; 141 138 142 - if (irqs_suspended) 139 + /* 140 + * If we're called to only run time-travel handlers then don't 141 + * actually proceed but mark sigio as pending (if applicable). 142 + * For suspend/resume, timetravel_handlers_only may be true 143 + * despite time-travel not being configured and used. 144 + */ 145 + if (timetravel_handlers_only) { 146 + #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 147 + mark_sigio_pending(); 148 + #endif 143 149 return; 150 + } 144 151 145 152 irq_io_loop(reg, regs); 146 153 } 147 154 148 - void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 155 + static void _sigio_handler(struct uml_pt_regs *regs, 156 + bool timetravel_handlers_only) 149 157 { 150 158 struct irq_entry *irq_entry; 151 159 int n, i; 152 160 153 - if (irqs_suspended && !um_irq_timetravel_handler_used()) 161 + if (timetravel_handlers_only && !um_irq_timetravel_handler_used()) 154 162 return; 155 163 156 164 while (1) { ··· 186 172 irq_entry = os_epoll_get_data_pointer(i); 187 173 188 174 for (t = 0; t < NUM_IRQ_TYPES; t++) 189 - sigio_reg_handler(i, irq_entry, t, regs); 175 + sigio_reg_handler(i, irq_entry, t, regs, 176 + timetravel_handlers_only); 190 177 } 191 178 } 192 179 193 - if (!irqs_suspended) 180 + if (!timetravel_handlers_only) 194 181 free_irqs(); 182 + } 183 + 184 + void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 185 + { 186 + _sigio_handler(regs, irqs_suspended); 195 187 } 196 188 197 189 static struct irq_entry *get_irq_entry_by_fd(int fd) ··· 419 399 420 400 void um_free_irq(int irq, void *dev) 421 401 { 422 - if (WARN(irq < 0 || irq > NR_IRQS, "freeing invalid irq %d", irq)) 402 + if (WARN(irq < 0 || irq > UM_LAST_SIGNAL_IRQ, 403 + "freeing invalid irq %d", irq)) 423 404 return; 424 405 425 406 free_irq_by_irq_and_dev(irq, dev); ··· 488 467 devname, dev_id, timetravel_handler); 489 468 } 490 469 EXPORT_SYMBOL(um_request_irq_tt); 470 + 471 + void sigio_run_timetravel_handlers(void) 472 + { 473 + _sigio_handler(NULL, true); 474 + } 491 475 #endif 492 476 493 477 #ifdef CONFIG_PM_SLEEP ··· 649 623 650 624 irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_edge_irq); 651 625 652 - for (i = 1; i < NR_IRQS; i++) 626 + for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++) 653 627 irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); 654 628 /* Initialize EPOLL Loop */ 655 629 os_setup_epoll();
+1 -1
arch/um/kernel/ksyms.c
··· 7 7 #include <os.h> 8 8 9 9 EXPORT_SYMBOL(set_signals); 10 - EXPORT_SYMBOL(get_signals); 10 + EXPORT_SYMBOL(signals_enabled); 11 11 12 12 EXPORT_SYMBOL(os_stat_fd); 13 13 EXPORT_SYMBOL(os_stat_file);
+1 -1
arch/um/kernel/skas/clone.c
··· 29 29 long err; 30 30 31 31 err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, 32 - (unsigned long)data + UM_KERN_PAGE_SIZE / 2 - sizeof(void *)); 32 + (unsigned long)data + UM_KERN_PAGE_SIZE / 2); 33 33 if (err) { 34 34 data->parent_err = err; 35 35 goto done;
+136
arch/um/kernel/skas/uaccess.c
··· 11 11 #include <asm/current.h> 12 12 #include <asm/page.h> 13 13 #include <kern_util.h> 14 + #include <asm/futex.h> 14 15 #include <os.h> 15 16 16 17 pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr) ··· 249 248 return 0; 250 249 } 251 250 EXPORT_SYMBOL(__strnlen_user); 251 + 252 + /** 253 + * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant 254 + * argument and comparison of the previous 255 + * futex value with another constant. 256 + * 257 + * @encoded_op: encoded operation to execute 258 + * @uaddr: pointer to user space address 259 + * 260 + * Return: 261 + * 0 - On success 262 + * -EFAULT - User access resulted in a page fault 263 + * -EAGAIN - Atomic operation was unable to complete due to contention 264 + * -ENOSYS - Operation not supported 265 + */ 266 + 267 + int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) 268 + { 269 + int oldval, ret; 270 + struct page *page; 271 + unsigned long addr = (unsigned long) uaddr; 272 + pte_t *pte; 273 + 274 + ret = -EFAULT; 275 + if (!access_ok(uaddr, sizeof(*uaddr))) 276 + return -EFAULT; 277 + preempt_disable(); 278 + pte = maybe_map(addr, 1); 279 + if (pte == NULL) 280 + goto out_inuser; 281 + 282 + page = pte_page(*pte); 283 + #ifdef CONFIG_64BIT 284 + pagefault_disable(); 285 + addr = (unsigned long) page_address(page) + 286 + (((unsigned long) addr) & ~PAGE_MASK); 287 + #else 288 + addr = (unsigned long) kmap_atomic(page) + 289 + ((unsigned long) addr & ~PAGE_MASK); 290 + #endif 291 + uaddr = (u32 *) addr; 292 + oldval = *uaddr; 293 + 294 + ret = 0; 295 + 296 + switch (op) { 297 + case FUTEX_OP_SET: 298 + *uaddr = oparg; 299 + break; 300 + case FUTEX_OP_ADD: 301 + *uaddr += oparg; 302 + break; 303 + case FUTEX_OP_OR: 304 + *uaddr |= oparg; 305 + break; 306 + case FUTEX_OP_ANDN: 307 + *uaddr &= ~oparg; 308 + break; 309 + case FUTEX_OP_XOR: 310 + *uaddr ^= oparg; 311 + break; 312 + default: 313 + ret = -ENOSYS; 314 + } 315 + #ifdef CONFIG_64BIT 316 + pagefault_enable(); 317 + #else 318 + kunmap_atomic((void *)addr); 319 + #endif 320 + 321 + out_inuser: 322 + preempt_enable(); 323 + 324 + if (ret == 0) 325 + *oval = oldval; 326 + 327 + return ret; 328 + } 329 + EXPORT_SYMBOL(arch_futex_atomic_op_inuser); 330 + 331 + /** 332 + * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the 333 + * uaddr with newval if the current value is 334 + * oldval. 335 + * @uval: pointer to store content of @uaddr 336 + * @uaddr: pointer to user space address 337 + * @oldval: old value 338 + * @newval: new value to store to @uaddr 339 + * 340 + * Return: 341 + * 0 - On success 342 + * -EFAULT - User access resulted in a page fault 343 + * -EAGAIN - Atomic operation was unable to complete due to contention 344 + * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) 345 + */ 346 + 347 + int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 348 + u32 oldval, u32 newval) 349 + { 350 + struct page *page; 351 + pte_t *pte; 352 + int ret = -EFAULT; 353 + 354 + if (!access_ok(uaddr, sizeof(*uaddr))) 355 + return -EFAULT; 356 + 357 + preempt_disable(); 358 + pte = maybe_map((unsigned long) uaddr, 1); 359 + if (pte == NULL) 360 + goto out_inatomic; 361 + 362 + page = pte_page(*pte); 363 + #ifdef CONFIG_64BIT 364 + pagefault_disable(); 365 + uaddr = page_address(page) + (((unsigned long) uaddr) & ~PAGE_MASK); 366 + #else 367 + uaddr = kmap_atomic(page) + ((unsigned long) uaddr & ~PAGE_MASK); 368 + #endif 369 + 370 + *uval = *uaddr; 371 + 372 + ret = cmpxchg(uaddr, oldval, newval); 373 + 374 + #ifdef CONFIG_64BIT 375 + pagefault_enable(); 376 + #else 377 + kunmap_atomic(uaddr); 378 + #endif 379 + ret = 0; 380 + 381 + out_inatomic: 382 + preempt_enable(); 383 + return ret; 384 + } 385 + EXPORT_SYMBOL(futex_atomic_cmpxchg_inatomic);
+12 -23
arch/um/kernel/time.c
··· 68 68 int ret; 69 69 70 70 /* 71 - * Poll outside the locked section (if we're not called to only read 72 - * the response) so we can get interrupts for e.g. virtio while we're 73 - * here, but then we need to lock to not get interrupted between the 74 - * read of the message and write of the ACK. 71 + * We can't unlock here, but interrupt signals with a timetravel_handler 72 + * (see um_request_irq_tt) get to the timetravel_handler anyway. 75 73 */ 76 74 if (mode != TTMH_READ) { 77 - bool disabled = irqs_disabled(); 75 + BUG_ON(mode == TTMH_IDLE && !irqs_disabled()); 78 76 79 - BUG_ON(mode == TTMH_IDLE && !disabled); 80 - 81 - if (disabled) 82 - local_irq_enable(); 83 77 while (os_poll(1, &time_travel_ext_fd) != 0) { 84 78 /* nothing */ 85 79 } 86 - if (disabled) 87 - local_irq_disable(); 88 80 } 89 81 90 82 ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg)); ··· 115 123 .time = time, 116 124 .seq = mseq, 117 125 }; 118 - unsigned long flags; 119 126 120 127 /* 121 - * We need to save interrupts here and only restore when we 122 - * got the ACK - otherwise we can get interrupted and send 123 - * another request while we're still waiting for an ACK, but 124 - * the peer doesn't know we got interrupted and will send 125 - * the ACKs in the same order as the message, but we'd need 126 - * to see them in the opposite order ... 128 + * We need to block even the timetravel handlers of SIGIO here and 129 + * only restore their use when we got the ACK - otherwise we may 130 + * (will) get interrupted by that, try to queue the IRQ for future 131 + * processing and thus send another request while we're still waiting 132 + * for an ACK, but the peer doesn't know we got interrupted and will 133 + * send the ACKs in the same order as the message, but we'd need to 134 + * see them in the opposite order ... 127 135 * 128 136 * This wouldn't matter *too* much, but some ACKs carry the 129 137 * current time (for UM_TIMETRAVEL_GET) and getting another ··· 132 140 * The sequence number assignment that happens here lets us 133 141 * debug such message handling issues more easily. 134 142 */ 135 - local_irq_save(flags); 143 + block_signals_hard(); 136 144 os_write_file(time_travel_ext_fd, &msg, sizeof(msg)); 137 145 138 146 while (msg.op != UM_TIMETRAVEL_ACK) ··· 144 152 145 153 if (op == UM_TIMETRAVEL_GET) 146 154 time_travel_set_time(msg.time); 147 - local_irq_restore(flags); 155 + unblock_signals_hard(); 148 156 149 157 return msg.time; 150 158 } ··· 344 352 while ((e = list_first_entry_or_null(&time_travel_irqs, 345 353 struct time_travel_event, 346 354 list))) { 347 - WARN(e->time != time_travel_time, 348 - "time moved from %lld to %lld before IRQ delivery\n", 349 - time_travel_time, e->time); 350 355 list_del(&e->list); 351 356 e->pending = false; 352 357 e->fn(e);
+44 -4
arch/um/kernel/um_arch.c
··· 6 6 #include <linux/delay.h> 7 7 #include <linux/init.h> 8 8 #include <linux/mm.h> 9 + #include <linux/ctype.h> 9 10 #include <linux/module.h> 10 11 #include <linux/panic_notifier.h> 11 12 #include <linux/seq_file.h> ··· 18 17 #include <linux/suspend.h> 19 18 20 19 #include <asm/processor.h> 20 + #include <asm/cpufeature.h> 21 21 #include <asm/sections.h> 22 22 #include <asm/setup.h> 23 23 #include <as-layout.h> ··· 53 51 */ 54 52 struct cpuinfo_um boot_cpu_data = { 55 53 .loops_per_jiffy = 0, 56 - .ipi_pipe = { -1, -1 } 54 + .ipi_pipe = { -1, -1 }, 55 + .cache_alignment = L1_CACHE_BYTES, 56 + .x86_capability = { 0 } 57 57 }; 58 + 59 + EXPORT_SYMBOL(boot_cpu_data); 58 60 59 61 union thread_union cpu0_irqstack 60 62 __section(".data..init_irqstack") = ··· 69 63 70 64 static int show_cpuinfo(struct seq_file *m, void *v) 71 65 { 72 - int index = 0; 66 + int i = 0; 73 67 74 - seq_printf(m, "processor\t: %d\n", index); 68 + seq_printf(m, "processor\t: %d\n", i); 75 69 seq_printf(m, "vendor_id\t: User Mode Linux\n"); 76 70 seq_printf(m, "model name\t: UML\n"); 77 71 seq_printf(m, "mode\t\t: skas\n"); 78 72 seq_printf(m, "host\t\t: %s\n", host_info); 79 - seq_printf(m, "bogomips\t: %lu.%02lu\n\n", 73 + seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no"); 74 + seq_printf(m, "flags\t\t:"); 75 + for (i = 0; i < 32*NCAPINTS; i++) 76 + if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL)) 77 + seq_printf(m, " %s", x86_cap_flags[i]); 78 + seq_printf(m, "\n"); 79 + seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment); 80 + seq_printf(m, "bogomips\t: %lu.%02lu\n", 80 81 loops_per_jiffy/(500000/HZ), 81 82 (loops_per_jiffy/(5000/HZ)) % 100); 83 + 82 84 83 85 return 0; 84 86 } ··· 276 262 277 263 #define MIN_VMALLOC (32 * 1024 * 1024) 278 264 265 + static void parse_host_cpu_flags(char *line) 266 + { 267 + int i; 268 + for (i = 0; i < 32*NCAPINTS; i++) { 269 + if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i])) 270 + set_cpu_cap(&boot_cpu_data, i); 271 + } 272 + } 273 + static void parse_cache_line(char *line) 274 + { 275 + long res; 276 + char *to_parse = strstr(line, ":"); 277 + if (to_parse) { 278 + to_parse++; 279 + while (*to_parse != 0 && isspace(*to_parse)) { 280 + to_parse++; 281 + } 282 + if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res)) 283 + boot_cpu_data.cache_alignment = res; 284 + else 285 + boot_cpu_data.cache_alignment = L1_CACHE_BYTES; 286 + } 287 + } 288 + 279 289 int __init linux_main(int argc, char **argv) 280 290 { 281 291 unsigned long avail, diff; ··· 335 297 336 298 /* OS sanity checks that need to happen before the kernel runs */ 337 299 os_early_checks(); 300 + 301 + get_host_cpu_features(parse_host_cpu_flags, parse_cache_line); 338 302 339 303 brk_start = (unsigned long) sbrk(0); 340 304
+2 -2
arch/um/os-Linux/helper.c
··· 64 64 goto out_close; 65 65 } 66 66 67 - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); 67 + sp = stack + UM_KERN_PAGE_SIZE; 68 68 data.pre_exec = pre_exec; 69 69 data.pre_data = pre_data; 70 70 data.argv = argv; ··· 120 120 if (stack == 0) 121 121 return -ENOMEM; 122 122 123 - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); 123 + sp = stack + UM_KERN_PAGE_SIZE; 124 124 pid = clone(proc, (void *) sp, flags, arg); 125 125 if (pid < 0) { 126 126 err = -errno;
+53 -11
arch/um/os-Linux/signal.c
··· 18 18 #include <sysdep/mcontext.h> 19 19 #include <um_malloc.h> 20 20 #include <sys/ucontext.h> 21 + #include <timetravel.h> 21 22 22 23 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { 23 24 [SIGTRAP] = relay_signal, ··· 63 62 #define SIGALRM_BIT 1 64 63 #define SIGALRM_MASK (1 << SIGALRM_BIT) 65 64 66 - static int signals_enabled; 65 + int signals_enabled; 66 + #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT 67 + static int signals_blocked; 68 + #else 69 + #define signals_blocked false 70 + #endif 67 71 static unsigned int signals_pending; 68 72 static unsigned int signals_active = 0; 69 73 70 74 void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) 71 75 { 72 - int enabled; 76 + int enabled = signals_enabled; 73 77 74 - enabled = signals_enabled; 75 - if (!enabled && (sig == SIGIO)) { 76 - signals_pending |= SIGIO_MASK; 78 + if ((signals_blocked || !enabled) && (sig == SIGIO)) { 79 + /* 80 + * In TT_MODE_EXTERNAL, need to still call time-travel 81 + * handlers unless signals are also blocked for the 82 + * external time message processing. This will mark 83 + * signals_pending by itself (only if necessary.) 84 + */ 85 + if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL) 86 + sigio_run_timetravel_handlers(); 87 + else 88 + signals_pending |= SIGIO_MASK; 77 89 return; 78 90 } 79 91 ··· 143 129 stack_t stack = { 144 130 .ss_flags = 0, 145 131 .ss_sp = sig_stack, 146 - .ss_size = size - sizeof(void *) 132 + .ss_size = size 147 133 }; 148 134 149 135 if (sigaltstack(&stack, NULL) != 0) ··· 348 334 } 349 335 } 350 336 351 - int get_signals(void) 352 - { 353 - return signals_enabled; 354 - } 355 - 356 337 int set_signals(int enable) 357 338 { 358 339 int ret; ··· 376 367 377 368 return ret; 378 369 } 370 + 371 + #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT 372 + void mark_sigio_pending(void) 373 + { 374 + signals_pending |= SIGIO_MASK; 375 + } 376 + 377 + void block_signals_hard(void) 378 + { 379 + if (signals_blocked) 380 + return; 381 + signals_blocked = 1; 382 + barrier(); 383 + } 384 + 385 + void unblock_signals_hard(void) 386 + { 387 + if (!signals_blocked) 388 + return; 389 + /* Must be set to 0 before we check the pending bits etc. */ 390 + signals_blocked = 0; 391 + barrier(); 392 + 393 + if (signals_pending && signals_enabled) { 394 + /* this is a bit inefficient, but that's not really important */ 395 + block_signals(); 396 + unblock_signals(); 397 + } else if (signals_pending & SIGIO_MASK) { 398 + /* we need to run time-travel handlers even if not enabled */ 399 + sigio_run_timetravel_handlers(); 400 + } 401 + } 402 + #endif 379 403 380 404 int os_is_signal_stack(void) 381 405 {
+1 -1
arch/um/os-Linux/skas/process.c
··· 327 327 } 328 328 329 329 /* set stack pointer to the end of the stack page, so it can grow downwards */ 330 - sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); 330 + sp = (unsigned long)stack + UM_KERN_PAGE_SIZE; 331 331 332 332 flags = CLONE_FILES | SIGCHLD; 333 333
+32
arch/um/os-Linux/start_up.c
··· 321 321 os_info("%llu\n", (unsigned long long)lim.rlim_max); 322 322 } 323 323 324 + void __init get_host_cpu_features( 325 + void (*flags_helper_func)(char *line), 326 + void (*cache_helper_func)(char *line)) 327 + { 328 + FILE *cpuinfo; 329 + char *line = NULL; 330 + size_t len = 0; 331 + int done_parsing = 0; 332 + 333 + cpuinfo = fopen("/proc/cpuinfo", "r"); 334 + if (cpuinfo == NULL) { 335 + os_info("Failed to get host CPU features\n"); 336 + } else { 337 + while ((getline(&line, &len, cpuinfo)) != -1) { 338 + if (strstr(line, "flags")) { 339 + flags_helper_func(line); 340 + done_parsing++; 341 + } 342 + if (strstr(line, "cache_alignment")) { 343 + cache_helper_func(line); 344 + done_parsing++; 345 + } 346 + free(line); 347 + line = NULL; 348 + if (done_parsing > 1) 349 + break; 350 + } 351 + fclose(cpuinfo); 352 + } 353 + } 354 + 355 + 324 356 void __init os_early_checks(void) 325 357 { 326 358 int pid;
+1 -1
arch/x86/Makefile.um
··· 44 44 45 45 # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example. 46 46 47 - LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64 47 + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64 48 48 LINK-y += -m64 49 49 50 50 endif
-1
drivers/input/Kconfig
··· 4 4 # 5 5 6 6 menu "Input device support" 7 - depends on !UML 8 7 9 8 config INPUT 10 9 tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
+1
drivers/input/gameport/Kconfig
··· 4 4 # 5 5 config GAMEPORT 6 6 tristate "Gameport support" 7 + depends on !UML 7 8 help 8 9 Gameport support is for the standard 15-pin PC gameport. If you 9 10 have a joystick, gamepad, gameport card, a soundcard with a gameport
+1
drivers/input/joystick/Kconfig
··· 4 4 # 5 5 menuconfig INPUT_JOYSTICK 6 6 bool "Joysticks/Gamepads" 7 + depends on !UML 7 8 help 8 9 If you have a joystick, 6dof controller, gamepad, steering wheel, 9 10 weapon control system or something like that you can say Y here
+2 -3
drivers/tty/Kconfig
··· 12 12 13 13 config VT 14 14 bool "Virtual terminal" if EXPERT 15 - depends on !UML 16 15 select INPUT 17 - default y 16 + default y if !UML 18 17 help 19 18 If you say Y here, you will get support for terminal devices with 20 19 display and keyboard devices. These are called "virtual" because you ··· 77 78 78 79 config HW_CONSOLE 79 80 bool 80 - depends on VT && !UML 81 + depends on VT 81 82 default y 82 83 83 84 config VT_HW_CONSOLE_BINDING
+1 -1
drivers/video/console/Kconfig
··· 9 9 bool "VGA text console" if EXPERT || !X86 10 10 depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ 11 11 (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ 12 - !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 12 + !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 && !UML 13 13 default y 14 14 help 15 15 Saying Y here will allow you to use Linux in text mode through a
+78
include/asm-generic/logic_io.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: johannes@sipsolutions.net 5 + */ 6 + #ifndef _LOGIC_IO_H 7 + #define _LOGIC_IO_H 8 + #include <linux/types.h> 9 + 10 + /* include this file into asm/io.h */ 11 + 12 + #ifdef CONFIG_INDIRECT_IOMEM 13 + 14 + #ifdef CONFIG_INDIRECT_IOMEM_FALLBACK 15 + /* 16 + * If you want emulated IO memory to fall back to 'normal' IO memory 17 + * if a region wasn't registered as emulated, then you need to have 18 + * all of the real_* functions implemented. 19 + */ 20 + #if !defined(real_ioremap) || !defined(real_iounmap) || \ 21 + !defined(real_raw_readb) || !defined(real_raw_writeb) || \ 22 + !defined(real_raw_readw) || !defined(real_raw_writew) || \ 23 + !defined(real_raw_readl) || !defined(real_raw_writel) || \ 24 + (defined(CONFIG_64BIT) && \ 25 + (!defined(real_raw_readq) || !defined(real_raw_writeq))) || \ 26 + !defined(real_memset_io) || \ 27 + !defined(real_memcpy_fromio) || \ 28 + !defined(real_memcpy_toio) 29 + #error "Must provide fallbacks for real IO memory access" 30 + #endif /* defined ... */ 31 + #endif /* CONFIG_INDIRECT_IOMEM_FALLBACK */ 32 + 33 + #define ioremap ioremap 34 + void __iomem *ioremap(phys_addr_t offset, size_t size); 35 + 36 + #define iounmap iounmap 37 + void iounmap(void __iomem *addr); 38 + 39 + #define __raw_readb __raw_readb 40 + u8 __raw_readb(const volatile void __iomem *addr); 41 + 42 + #define __raw_readw __raw_readw 43 + u16 __raw_readw(const volatile void __iomem *addr); 44 + 45 + #define __raw_readl __raw_readl 46 + u32 __raw_readl(const volatile void __iomem *addr); 47 + 48 + #ifdef CONFIG_64BIT 49 + #define __raw_readq __raw_readq 50 + u64 __raw_readq(const volatile void __iomem *addr); 51 + #endif /* CONFIG_64BIT */ 52 + 53 + #define __raw_writeb __raw_writeb 54 + void __raw_writeb(u8 value, volatile void __iomem *addr); 55 + 56 + #define __raw_writew __raw_writew 57 + void __raw_writew(u16 value, volatile void __iomem *addr); 58 + 59 + #define __raw_writel __raw_writel 60 + void __raw_writel(u32 value, volatile void __iomem *addr); 61 + 62 + #ifdef CONFIG_64BIT 63 + #define __raw_writeq __raw_writeq 64 + void __raw_writeq(u64 value, volatile void __iomem *addr); 65 + #endif /* CONFIG_64BIT */ 66 + 67 + #define memset_io memset_io 68 + void memset_io(volatile void __iomem *addr, int value, size_t size); 69 + 70 + #define memcpy_fromio memcpy_fromio 71 + void memcpy_fromio(void *buffer, const volatile void __iomem *addr, 72 + size_t size); 73 + 74 + #define memcpy_toio memcpy_toio 75 + void memcpy_toio(volatile void __iomem *addr, const void *buffer, size_t size); 76 + 77 + #endif /* CONFIG_INDIRECT_IOMEM */ 78 + #endif /* _LOGIC_IO_H */
+62
include/linux/logic_iomem.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: johannes@sipsolutions.net 5 + */ 6 + #ifndef __LOGIC_IOMEM_H 7 + #define __LOGIC_IOMEM_H 8 + #include <linux/types.h> 9 + #include <linux/ioport.h> 10 + 11 + /** 12 + * struct logic_iomem_ops - emulated IO memory ops 13 + * @read: read an 8, 16, 32 or 64 bit quantity from the given offset, 14 + * size is given in bytes (1, 2, 4 or 8) 15 + * (64-bit only necessary if CONFIG_64BIT is set) 16 + * @write: write an 8, 16 32 or 64 bit quantity to the given offset, 17 + * size is given in bytes (1, 2, 4 or 8) 18 + * (64-bit only necessary if CONFIG_64BIT is set) 19 + * @set: optional, for memset_io() 20 + * @copy_from: optional, for memcpy_fromio() 21 + * @copy_to: optional, for memcpy_toio() 22 + * @unmap: optional, this region is getting unmapped 23 + */ 24 + struct logic_iomem_ops { 25 + unsigned long (*read)(void *priv, unsigned int offset, int size); 26 + void (*write)(void *priv, unsigned int offset, int size, 27 + unsigned long val); 28 + 29 + void (*set)(void *priv, unsigned int offset, u8 value, int size); 30 + void (*copy_from)(void *priv, void *buffer, unsigned int offset, 31 + int size); 32 + void (*copy_to)(void *priv, unsigned int offset, const void *buffer, 33 + int size); 34 + 35 + void (*unmap)(void *priv); 36 + }; 37 + 38 + /** 39 + * struct logic_iomem_region_ops - ops for an IO memory handler 40 + * @map: map a range in the registered IO memory region, must 41 + * fill *ops with the ops and may fill *priv to be passed 42 + * to the ops. The offset is given as the offset into the 43 + * registered resource region. 44 + * The return value is negative for errors, or >= 0 for 45 + * success. On success, the return value is added to the 46 + * offset for later ops, to allow for partial mappings. 47 + */ 48 + struct logic_iomem_region_ops { 49 + long (*map)(unsigned long offset, size_t size, 50 + const struct logic_iomem_ops **ops, 51 + void **priv); 52 + }; 53 + 54 + /** 55 + * logic_iomem_add_region - register an IO memory region 56 + * @resource: the resource description for this region 57 + * @ops: the IO memory mapping ops for this resource 58 + */ 59 + int logic_iomem_add_region(struct resource *resource, 60 + const struct logic_iomem_region_ops *ops); 61 + 62 + #endif /* __LOGIC_IOMEM_H */
+64
include/uapi/linux/virtio_pcidev.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + #ifndef _UAPI_LINUX_VIRTIO_PCIDEV_H 7 + #define _UAPI_LINUX_VIRTIO_PCIDEV_H 8 + #include <linux/types.h> 9 + 10 + /** 11 + * enum virtio_pcidev_ops - virtual PCI device operations 12 + * @VIRTIO_PCIDEV_OP_CFG_READ: read config space, size is 1, 2, 4 or 8; 13 + * the @data field should be filled in by the device (in little endian). 14 + * @VIRTIO_PCIDEV_OP_CFG_WRITE: write config space, size is 1, 2, 4 or 8; 15 + * the @data field contains the data to write (in little endian). 16 + * @VIRTIO_PCIDEV_OP_BAR_READ: read BAR mem/pio, size can be variable; 17 + * the @data field should be filled in by the device (in little endian). 18 + * @VIRTIO_PCIDEV_OP_BAR_WRITE: write BAR mem/pio, size can be variable; 19 + * the @data field contains the data to write (in little endian). 20 + * @VIRTIO_PCIDEV_OP_MMIO_MEMSET: memset MMIO, size is variable but 21 + * the @data field only has one byte (unlike @VIRTIO_PCIDEV_OP_MMIO_WRITE) 22 + * @VIRTIO_PCIDEV_OP_INT: legacy INTx# pin interrupt, the addr field is 1-4 for 23 + * the number 24 + * @VIRTIO_PCIDEV_OP_MSI: MSI(-X) interrupt, this message basically transports 25 + * the 16- or 32-bit write that would otherwise be done into memory, 26 + * analogous to the write messages (@VIRTIO_PCIDEV_OP_MMIO_WRITE) above 27 + * @VIRTIO_PCIDEV_OP_PME: Dummy message whose content is ignored (and should be 28 + * all zeroes) to signal the PME# pin. 29 + */ 30 + enum virtio_pcidev_ops { 31 + VIRTIO_PCIDEV_OP_RESERVED = 0, 32 + VIRTIO_PCIDEV_OP_CFG_READ, 33 + VIRTIO_PCIDEV_OP_CFG_WRITE, 34 + VIRTIO_PCIDEV_OP_MMIO_READ, 35 + VIRTIO_PCIDEV_OP_MMIO_WRITE, 36 + VIRTIO_PCIDEV_OP_MMIO_MEMSET, 37 + VIRTIO_PCIDEV_OP_INT, 38 + VIRTIO_PCIDEV_OP_MSI, 39 + VIRTIO_PCIDEV_OP_PME, 40 + }; 41 + 42 + /** 43 + * struct virtio_pcidev_msg - virtio PCI device operation 44 + * @op: the operation to do 45 + * @bar: the bar (only with BAR read/write messages) 46 + * @reserved: reserved 47 + * @size: the size of the read/write (in bytes) 48 + * @addr: the address to read/write 49 + * @data: the data, normally @size long, but just one byte for 50 + * %VIRTIO_PCIDEV_OP_MMIO_MEMSET 51 + * 52 + * Note: the fields are all in native (CPU) endian, however, the 53 + * @data values will often be in little endian (see the ops above.) 54 + */ 55 + struct virtio_pcidev_msg { 56 + __u8 op; 57 + __u8 bar; 58 + __u16 reserved; 59 + __u32 size; 60 + __u64 addr; 61 + __u8 data[]; 62 + }; 63 + 64 + #endif /* _UAPI_LINUX_VIRTIO_PCIDEV_H */
+14
lib/Kconfig
··· 102 102 103 103 When in doubt, say N. 104 104 105 + config INDIRECT_IOMEM 106 + bool 107 + help 108 + This is selected by other options/architectures to provide the 109 + emulated iomem accessors. 110 + 111 + config INDIRECT_IOMEM_FALLBACK 112 + bool 113 + depends on INDIRECT_IOMEM 114 + help 115 + If INDIRECT_IOMEM is selected, this enables falling back to plain 116 + mmio accesses when the IO memory address is not a registered 117 + emulated region. 118 + 105 119 config CRC_CCITT 106 120 tristate "CRC-CCITT functions" 107 121 help
+2
lib/Makefile
··· 148 148 149 149 lib-y += logic_pio.o 150 150 151 + lib-$(CONFIG_INDIRECT_IOMEM) += logic_iomem.o 152 + 151 153 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o 152 154 153 155 obj-$(CONFIG_BTREE) += btree.o
+318
lib/logic_iomem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + #include <linux/types.h> 7 + #include <linux/slab.h> 8 + #include <linux/logic_iomem.h> 9 + 10 + struct logic_iomem_region { 11 + const struct resource *res; 12 + const struct logic_iomem_region_ops *ops; 13 + struct list_head list; 14 + }; 15 + 16 + struct logic_iomem_area { 17 + const struct logic_iomem_ops *ops; 18 + void *priv; 19 + }; 20 + 21 + #define AREA_SHIFT 24 22 + #define MAX_AREA_SIZE (1 << AREA_SHIFT) 23 + #define MAX_AREAS ((1ULL<<32) / MAX_AREA_SIZE) 24 + #define AREA_BITS ((MAX_AREAS - 1) << AREA_SHIFT) 25 + #define AREA_MASK (MAX_AREA_SIZE - 1) 26 + #ifdef CONFIG_64BIT 27 + #define IOREMAP_BIAS 0xDEAD000000000000UL 28 + #define IOREMAP_MASK 0xFFFFFFFF00000000UL 29 + #else 30 + #define IOREMAP_BIAS 0 31 + #define IOREMAP_MASK 0 32 + #endif 33 + 34 + static DEFINE_MUTEX(regions_mtx); 35 + static LIST_HEAD(regions_list); 36 + static struct logic_iomem_area mapped_areas[MAX_AREAS]; 37 + 38 + int logic_iomem_add_region(struct resource *resource, 39 + const struct logic_iomem_region_ops *ops) 40 + { 41 + struct logic_iomem_region *rreg; 42 + int err; 43 + 44 + if (WARN_ON(!resource || !ops)) 45 + return -EINVAL; 46 + 47 + if (WARN_ON((resource->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM)) 48 + return -EINVAL; 49 + 50 + rreg = kzalloc(sizeof(*rreg), GFP_KERNEL); 51 + if (!rreg) 52 + return -ENOMEM; 53 + 54 + err = request_resource(&iomem_resource, resource); 55 + if (err) { 56 + kfree(rreg); 57 + return -ENOMEM; 58 + } 59 + 60 + mutex_lock(&regions_mtx); 61 + rreg->res = resource; 62 + rreg->ops = ops; 63 + list_add_tail(&rreg->list, &regions_list); 64 + mutex_unlock(&regions_mtx); 65 + 66 + return 0; 67 + } 68 + EXPORT_SYMBOL(logic_iomem_add_region); 69 + 70 + #ifndef CONFIG_LOGIC_IOMEM_FALLBACK 71 + static void __iomem *real_ioremap(phys_addr_t offset, size_t size) 72 + { 73 + WARN(1, "invalid ioremap(0x%llx, 0x%zx)\n", 74 + (unsigned long long)offset, size); 75 + return NULL; 76 + } 77 + 78 + static void real_iounmap(void __iomem *addr) 79 + { 80 + WARN(1, "invalid iounmap for addr 0x%llx\n", 81 + (unsigned long long)addr); 82 + } 83 + #endif /* CONFIG_LOGIC_IOMEM_FALLBACK */ 84 + 85 + void __iomem *ioremap(phys_addr_t offset, size_t size) 86 + { 87 + void __iomem *ret = NULL; 88 + struct logic_iomem_region *rreg, *found = NULL; 89 + int i; 90 + 91 + mutex_lock(&regions_mtx); 92 + list_for_each_entry(rreg, &regions_list, list) { 93 + if (rreg->res->start > offset) 94 + continue; 95 + if (rreg->res->end < offset + size - 1) 96 + continue; 97 + found = rreg; 98 + break; 99 + } 100 + 101 + if (!found) 102 + goto out; 103 + 104 + for (i = 0; i < MAX_AREAS; i++) { 105 + long offs; 106 + 107 + if (mapped_areas[i].ops) 108 + continue; 109 + 110 + offs = rreg->ops->map(offset - found->res->start, 111 + size, &mapped_areas[i].ops, 112 + &mapped_areas[i].priv); 113 + if (offs < 0) { 114 + mapped_areas[i].ops = NULL; 115 + break; 116 + } 117 + 118 + if (WARN_ON(!mapped_areas[i].ops)) { 119 + mapped_areas[i].ops = NULL; 120 + break; 121 + } 122 + 123 + ret = (void __iomem *)(IOREMAP_BIAS + (i << AREA_SHIFT) + offs); 124 + break; 125 + } 126 + out: 127 + mutex_unlock(&regions_mtx); 128 + if (ret) 129 + return ret; 130 + return real_ioremap(offset, size); 131 + } 132 + EXPORT_SYMBOL(ioremap); 133 + 134 + static inline struct logic_iomem_area * 135 + get_area(const volatile void __iomem *addr) 136 + { 137 + unsigned long a = (unsigned long)addr; 138 + unsigned int idx; 139 + 140 + if (WARN_ON((a & IOREMAP_MASK) != IOREMAP_BIAS)) 141 + return NULL; 142 + 143 + idx = (a & AREA_BITS) >> AREA_SHIFT; 144 + 145 + if (mapped_areas[idx].ops) 146 + return &mapped_areas[idx]; 147 + 148 + return NULL; 149 + } 150 + 151 + void iounmap(void __iomem *addr) 152 + { 153 + struct logic_iomem_area *area = get_area(addr); 154 + 155 + if (!area) { 156 + real_iounmap(addr); 157 + return; 158 + } 159 + 160 + if (area->ops->unmap) 161 + area->ops->unmap(area->priv); 162 + 163 + mutex_lock(&regions_mtx); 164 + area->ops = NULL; 165 + area->priv = NULL; 166 + mutex_unlock(&regions_mtx); 167 + } 168 + EXPORT_SYMBOL(iounmap); 169 + 170 + #ifndef CONFIG_LOGIC_IOMEM_FALLBACK 171 + #define MAKE_FALLBACK(op, sz) \ 172 + static u##sz real_raw_read ## op(const volatile void __iomem *addr) \ 173 + { \ 174 + WARN(1, "Invalid read" #op " at address %llx\n", \ 175 + (unsigned long long)addr); \ 176 + return (u ## sz)~0ULL; \ 177 + } \ 178 + \ 179 + void real_raw_write ## op(u ## sz val, volatile void __iomem *addr) \ 180 + { \ 181 + WARN(1, "Invalid writeq" #op " of 0x%llx at address %llx\n", \ 182 + (unsigned long long)val, (unsigned long long)addr); \ 183 + } \ 184 + 185 + MAKE_FALLBACK(b, 8); 186 + MAKE_FALLBACK(w, 16); 187 + MAKE_FALLBACK(l, 32); 188 + #ifdef CONFIG_64BIT 189 + MAKE_FALLBACK(q, 64); 190 + #endif 191 + 192 + static void real_memset_io(volatile void __iomem *addr, int value, size_t size) 193 + { 194 + WARN(1, "Invalid memset_io at address 0x%llx\n", 195 + (unsigned long long)addr); 196 + } 197 + 198 + static void real_memcpy_fromio(void *buffer, const volatile void __iomem *addr, 199 + size_t size) 200 + { 201 + WARN(1, "Invalid memcpy_fromio at address 0x%llx\n", 202 + (unsigned long long)addr); 203 + 204 + memset(buffer, 0xff, size); 205 + } 206 + 207 + static void real_memcpy_toio(volatile void __iomem *addr, const void *buffer, 208 + size_t size) 209 + { 210 + WARN(1, "Invalid memcpy_toio at address 0x%llx\n", 211 + (unsigned long long)addr); 212 + } 213 + #endif /* CONFIG_LOGIC_IOMEM_FALLBACK */ 214 + 215 + #define MAKE_OP(op, sz) \ 216 + u##sz __raw_read ## op(const volatile void __iomem *addr) \ 217 + { \ 218 + struct logic_iomem_area *area = get_area(addr); \ 219 + \ 220 + if (!area) \ 221 + return real_raw_read ## op(addr); \ 222 + \ 223 + return (u ## sz) area->ops->read(area->priv, \ 224 + (unsigned long)addr & AREA_MASK,\ 225 + sz / 8); \ 226 + } \ 227 + EXPORT_SYMBOL(__raw_read ## op); \ 228 + \ 229 + void __raw_write ## op(u ## sz val, volatile void __iomem *addr) \ 230 + { \ 231 + struct logic_iomem_area *area = get_area(addr); \ 232 + \ 233 + if (!area) { \ 234 + real_raw_write ## op(val, addr); \ 235 + return; \ 236 + } \ 237 + \ 238 + area->ops->write(area->priv, \ 239 + (unsigned long)addr & AREA_MASK, \ 240 + sz / 8, val); \ 241 + } \ 242 + EXPORT_SYMBOL(__raw_write ## op) 243 + 244 + MAKE_OP(b, 8); 245 + MAKE_OP(w, 16); 246 + MAKE_OP(l, 32); 247 + #ifdef CONFIG_64BIT 248 + MAKE_OP(q, 64); 249 + #endif 250 + 251 + void memset_io(volatile void __iomem *addr, int value, size_t size) 252 + { 253 + struct logic_iomem_area *area = get_area(addr); 254 + unsigned long offs, start; 255 + 256 + if (!area) { 257 + real_memset_io(addr, value, size); 258 + return; 259 + } 260 + 261 + start = (unsigned long)addr & AREA_MASK; 262 + 263 + if (area->ops->set) { 264 + area->ops->set(area->priv, start, value, size); 265 + return; 266 + } 267 + 268 + for (offs = 0; offs < size; offs++) 269 + area->ops->write(area->priv, start + offs, 1, value); 270 + } 271 + EXPORT_SYMBOL(memset_io); 272 + 273 + void memcpy_fromio(void *buffer, const volatile void __iomem *addr, 274 + size_t size) 275 + { 276 + struct logic_iomem_area *area = get_area(addr); 277 + u8 *buf = buffer; 278 + unsigned long offs, start; 279 + 280 + if (!area) { 281 + real_memcpy_fromio(buffer, addr, size); 282 + return; 283 + } 284 + 285 + start = (unsigned long)addr & AREA_MASK; 286 + 287 + if (area->ops->copy_from) { 288 + area->ops->copy_from(area->priv, buffer, start, size); 289 + return; 290 + } 291 + 292 + for (offs = 0; offs < size; offs++) 293 + buf[offs] = area->ops->read(area->priv, start + offs, 1); 294 + } 295 + EXPORT_SYMBOL(memcpy_fromio); 296 + 297 + void memcpy_toio(volatile void __iomem *addr, const void *buffer, size_t size) 298 + { 299 + struct logic_iomem_area *area = get_area(addr); 300 + const u8 *buf = buffer; 301 + unsigned long offs, start; 302 + 303 + if (!area) { 304 + real_memcpy_toio(addr, buffer, size); 305 + return; 306 + } 307 + 308 + start = (unsigned long)addr & AREA_MASK; 309 + 310 + if (area->ops->copy_to) { 311 + area->ops->copy_to(area->priv, start, buffer, size); 312 + return; 313 + } 314 + 315 + for (offs = 0; offs < size; offs++) 316 + area->ops->write(area->priv, start + offs, 1, buf[offs]); 317 + } 318 + EXPORT_SYMBOL(memcpy_toio);