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

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

Pull UML updates from Richard Weinberger:

- Support for preemption

- i386 Rust support

- Huge cleanup by Benjamin Berg

- UBSAN support

- Removal of dead code

* tag 'uml-for-linus-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux: (41 commits)
um: vector: always reset vp->opened
um: vector: remove vp->lock
um: register power-off handler
um: line: always fill *error_out in setup_one_line()
um: remove pcap driver from documentation
um: Enable preemption in UML
um: refactor TLB update handling
um: simplify and consolidate TLB updates
um: remove force_flush_all from fork_handler
um: Do not flush MM in flush_thread
um: Delay flushing syscalls until the thread is restarted
um: remove copy_context_skas0
um: remove LDT support
um: compress memory related stub syscalls while adding them
um: Rework syscall handling
um: Add generic stub_syscall6 function
um: Create signal stack memory assignment in stub_data
um: Remove stub-data.h include from common-offsets.h
um: time-travel: fix signal blocking race/hang
um: time-travel: remove time_exit()
...

+1312 -1971
+1 -1
Documentation/rust/arch-support.rst
··· 18 18 ``arm64`` Maintained Little Endian only. 19 19 ``loongarch`` Maintained \- 20 20 ``riscv`` Maintained ``riscv64`` only. 21 - ``um`` Maintained ``x86_64`` only. 21 + ``um`` Maintained \- 22 22 ``x86`` Maintained ``x86_64`` only. 23 23 ============= ================ ============================================== 24 24
-2
Documentation/virt/uml/user_mode_linux_howto_v2.rst
··· 223 223 +-----------+--------+------------------------------------+------------+ 224 224 | socket | legacy | none | ~ 450Mbit | 225 225 +-----------+--------+------------------------------------+------------+ 226 - | pcap | legacy | rx only | ~ 450Mbit | 227 - +-----------+--------+------------------------------------+------------+ 228 226 | ethertap | legacy | obsolete | ~ 500Mbit | 229 227 +-----------+--------+------------------------------------+------------+ 230 228 | vde | legacy | obsolete | ~ 500Mbit |
+5 -3
arch/um/Kconfig
··· 11 11 select ARCH_HAS_KCOV 12 12 select ARCH_HAS_STRNCPY_FROM_USER 13 13 select ARCH_HAS_STRNLEN_USER 14 - select ARCH_NO_PREEMPT 14 + select ARCH_NO_PREEMPT_DYNAMIC 15 15 select HAVE_ARCH_AUDITSYSCALL 16 16 select HAVE_ARCH_KASAN if X86_64 17 17 select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN ··· 31 31 select TRACE_IRQFLAGS_SUPPORT 32 32 select TTY # Needed for line.c 33 33 select HAVE_ARCH_VMAP_STACK 34 - select HAVE_RUST if X86_64 34 + select HAVE_RUST 35 + select ARCH_HAS_UBSAN 35 36 36 37 config MMU 37 38 bool ··· 49 48 config UML_IOMEM_EMULATION 50 49 bool 51 50 select INDIRECT_IOMEM 51 + select HAS_IOPORT 52 52 select GENERIC_PCI_IOMAP 53 53 select GENERIC_IOMAP 54 54 select NO_GENERIC_PCI_IOPORT_MAP 55 55 56 56 config NO_IOPORT_MAP 57 - def_bool y 57 + def_bool !UML_IOMEM_EMULATION 58 58 59 59 config ISA 60 60 bool
-20
arch/um/drivers/Kconfig
··· 297 297 298 298 If unsure, say N. 299 299 300 - config UML_NET_PCAP 301 - bool "pcap transport (obsolete)" 302 - depends on UML_NET 303 - depends on !MODVERSIONS 304 - select MAY_HAVE_RUNTIME_DEPS 305 - help 306 - The pcap transport makes a pcap packet stream on the host look 307 - like an ethernet device inside UML. This is useful for making 308 - UML act as a network monitor for the host. You must have libcap 309 - installed in order to build the pcap transport into UML. 310 - 311 - For more information, see 312 - <http://user-mode-linux.sourceforge.net/old/networking.html> That site 313 - has examples of the UML command line to use to enable this option. 314 - 315 - NOTE: THIS TRANSPORT IS DEPRECATED AND WILL BE REMOVED SOON!!! Please 316 - migrate to UML_NET_VECTOR. 317 - 318 - If unsure, say N. 319 - 320 300 config UML_NET_SLIRP 321 301 bool "SLiRP transport (obsolete)" 322 302 depends on UML_NET
+2 -8
arch/um/drivers/Makefile
··· 20 20 harddog-builtin-$(CONFIG_UML_WATCHDOG) := harddog_user.o harddog_user_exp.o 21 21 rtc-objs := rtc_kern.o rtc_user.o 22 22 23 - LDFLAGS_pcap.o = $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libpcap.a) 24 - 25 23 LDFLAGS_vde.o = $(shell $(CC) $(CFLAGS) -print-file-name=libvdeplug.a) 26 24 27 - targets := pcap_kern.o pcap_user.o vde_kern.o vde_user.o 28 - 29 - $(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o 30 - $(LD) -r -dp -o $@ $^ $(ld_flags) 25 + targets := vde_kern.o vde_user.o 31 26 32 27 $(obj)/vde.o: $(obj)/vde_kern.o $(obj)/vde_user.o 33 28 $(LD) -r -dp -o $@ $^ $(ld_flags) ··· 44 49 obj-$(CONFIG_UML_NET_VECTOR) += vector.o 45 50 obj-$(CONFIG_UML_NET_VDE) += vde.o 46 51 obj-$(CONFIG_UML_NET_MCAST) += umcast.o 47 - obj-$(CONFIG_UML_NET_PCAP) += pcap.o 48 52 obj-$(CONFIG_UML_NET) += net.o 49 53 obj-$(CONFIG_MCONSOLE) += mconsole.o 50 54 obj-$(CONFIG_MMAPPER) += mmapper_kern.o ··· 63 69 obj-$(CONFIG_UML_PCI_OVER_VIRTIO) += virt-pci.o 64 70 65 71 # pcap_user.o must be added explicitly. 66 - USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o 72 + USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o vde_user.o vector_user.o 67 73 CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH) 68 74 69 75 CFLAGS_xterm.o += '-DCONFIG_XTERM_CHAN_DEFAULT_EMULATOR="$(CONFIG_XTERM_CHAN_DEFAULT_EMULATOR)"'
+2 -1
arch/um/drivers/chan.h
··· 22 22 unsigned int output:1; 23 23 unsigned int opened:1; 24 24 unsigned int enabled:1; 25 - int fd; 25 + int fd_in; 26 + int fd_out; /* only different to fd_in if blocking output is needed */ 26 27 const struct chan_ops *ops; 27 28 void *data; 28 29 };
+61 -20
arch/um/drivers/chan_kern.c
··· 81 81 }; 82 82 #endif /* CONFIG_NOCONFIG_CHAN */ 83 83 84 + static inline bool need_output_blocking(void) 85 + { 86 + return time_travel_mode == TT_MODE_INFCPU || 87 + time_travel_mode == TT_MODE_EXTERNAL; 88 + } 89 + 84 90 static int open_one_chan(struct chan *chan) 85 91 { 86 92 int fd, err; ··· 102 96 return fd; 103 97 104 98 err = os_set_fd_block(fd, 0); 105 - if (err) { 106 - (*chan->ops->close)(fd, chan->data); 107 - return err; 108 - } 99 + if (err) 100 + goto out_close; 109 101 110 - chan->fd = fd; 102 + chan->fd_in = fd; 103 + chan->fd_out = fd; 104 + 105 + /* 106 + * In time-travel modes infinite-CPU and external we need to guarantee 107 + * that any writes to the output succeed immdiately from the point of 108 + * the VM. The best way to do this is to put the FD in blocking mode 109 + * and simply wait/retry until everything is written. 110 + * As every write is guaranteed to complete, we also do not need to 111 + * request an IRQ for the output. 112 + * 113 + * Note that input cannot happen in a time synchronized way. We permit 114 + * it, but time passes very quickly if anything waits for a read. 115 + */ 116 + if (chan->output && need_output_blocking()) { 117 + err = os_dup_file(chan->fd_out); 118 + if (err < 0) 119 + goto out_close; 120 + 121 + chan->fd_out = err; 122 + 123 + err = os_set_fd_block(chan->fd_out, 1); 124 + if (err) { 125 + os_close_file(chan->fd_out); 126 + goto out_close; 127 + } 128 + } 111 129 112 130 chan->opened = 1; 113 131 return 0; 132 + 133 + out_close: 134 + (*chan->ops->close)(fd, chan->data); 135 + return err; 114 136 } 115 137 116 138 static int open_chan(struct list_head *chans) ··· 159 125 void chan_enable_winch(struct chan *chan, struct tty_port *port) 160 126 { 161 127 if (chan && chan->primary && chan->ops->winch) 162 - register_winch(chan->fd, port); 128 + register_winch(chan->fd_in, port); 163 129 } 164 130 165 131 static void line_timer_cb(struct work_struct *work) ··· 190 156 191 157 if (chan->enabled) 192 158 continue; 193 - err = line_setup_irq(chan->fd, chan->input, chan->output, line, 194 - chan); 159 + err = line_setup_irq(chan->fd_in, chan->input, 160 + chan->output && !need_output_blocking(), 161 + line, chan); 195 162 if (err) 196 163 goto out_close; 197 164 ··· 231 196 232 197 if (chan->input && chan->enabled) 233 198 um_free_irq(chan->line->read_irq, chan); 234 - if (chan->output && chan->enabled) 199 + if (chan->output && chan->enabled && 200 + !need_output_blocking()) 235 201 um_free_irq(chan->line->write_irq, chan); 236 202 chan->enabled = 0; 237 203 } ··· 252 216 } else { 253 217 if (chan->input && chan->enabled) 254 218 um_free_irq(chan->line->read_irq, chan); 255 - if (chan->output && chan->enabled) 219 + if (chan->output && chan->enabled && 220 + !need_output_blocking()) 256 221 um_free_irq(chan->line->write_irq, chan); 257 222 chan->enabled = 0; 258 223 } 224 + if (chan->fd_out != chan->fd_in) 225 + os_close_file(chan->fd_out); 259 226 if (chan->ops->close != NULL) 260 - (*chan->ops->close)(chan->fd, chan->data); 227 + (*chan->ops->close)(chan->fd_in, chan->data); 261 228 262 229 chan->opened = 0; 263 - chan->fd = -1; 230 + chan->fd_in = -1; 231 + chan->fd_out = -1; 264 232 } 265 233 266 234 void close_chan(struct line *line) ··· 284 244 void deactivate_chan(struct chan *chan, int irq) 285 245 { 286 246 if (chan && chan->enabled) 287 - deactivate_fd(chan->fd, irq); 247 + deactivate_fd(chan->fd_in, irq); 288 248 } 289 249 290 250 int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq) ··· 294 254 if (len == 0 || !chan || !chan->ops->write) 295 255 return 0; 296 256 297 - n = chan->ops->write(chan->fd, buf, len, chan->data); 257 + n = chan->ops->write(chan->fd_out, buf, len, chan->data); 298 258 if (chan->primary) { 299 259 ret = n; 300 260 } ··· 308 268 if (!chan || !chan->ops->console_write) 309 269 return 0; 310 270 311 - n = chan->ops->console_write(chan->fd, buf, len); 271 + n = chan->ops->console_write(chan->fd_out, buf, len); 312 272 if (chan->primary) 313 273 ret = n; 314 274 return ret; ··· 336 296 if (chan && chan->primary) { 337 297 if (chan->ops->window_size == NULL) 338 298 return 0; 339 - return chan->ops->window_size(chan->fd, chan->data, 299 + return chan->ops->window_size(chan->fd_in, chan->data, 340 300 rows_out, cols_out); 341 301 } 342 302 chan = line->chan_out; 343 303 if (chan && chan->primary) { 344 304 if (chan->ops->window_size == NULL) 345 305 return 0; 346 - return chan->ops->window_size(chan->fd, chan->data, 306 + return chan->ops->window_size(chan->fd_in, chan->data, 347 307 rows_out, cols_out); 348 308 } 349 309 return 0; ··· 359 319 (*chan->ops->free)(chan->data); 360 320 361 321 if (chan->primary && chan->output) 362 - ignore_sigio_fd(chan->fd); 322 + ignore_sigio_fd(chan->fd_in); 363 323 kfree(chan); 364 324 } 365 325 ··· 518 478 .output = 0, 519 479 .opened = 0, 520 480 .enabled = 0, 521 - .fd = -1, 481 + .fd_in = -1, 482 + .fd_out = -1, 522 483 .ops = ops, 523 484 .data = data }); 524 485 return chan; ··· 590 549 schedule_delayed_work(&line->task, 1); 591 550 goto out; 592 551 } 593 - err = chan->ops->read(chan->fd, &c, chan->data); 552 + err = chan->ops->read(chan->fd_in, &c, chan->data); 594 553 if (err > 0) 595 554 tty_insert_flip_char(port, c, TTY_NORMAL); 596 555 } while (err > 0);
+16 -4
arch/um/drivers/chan_user.c
··· 23 23 { 24 24 int n; 25 25 26 - n = read(fd, c_out, sizeof(*c_out)); 26 + CATCH_EINTR(n = read(fd, c_out, sizeof(*c_out))); 27 27 if (n > 0) 28 28 return n; 29 29 else if (n == 0) ··· 37 37 38 38 int generic_write(int fd, const __u8 *buf, size_t n, void *unused) 39 39 { 40 + int written = 0; 40 41 int err; 41 42 42 - err = write(fd, buf, n); 43 - if (err > 0) 44 - return err; 43 + /* The FD may be in blocking mode, as such, need to retry short writes, 44 + * they may have been interrupted by a signal. 45 + */ 46 + do { 47 + errno = 0; 48 + err = write(fd, buf + written, n - written); 49 + if (err > 0) { 50 + written += err; 51 + continue; 52 + } 53 + } while (err < 0 && errno == EINTR); 54 + 55 + if (written > 0) 56 + return written; 45 57 else if (errno == EAGAIN) 46 58 return 0; 47 59 else if (err == 0)
+1
arch/um/drivers/harddog_kern.c
··· 49 49 #include "mconsole.h" 50 50 #include "harddog.h" 51 51 52 + MODULE_DESCRIPTION("UML hardware watchdog"); 52 53 MODULE_LICENSE("GPL"); 53 54 54 55 static DEFINE_MUTEX(harddog_mutex);
+2
arch/um/drivers/line.c
··· 383 383 parse_chan_pair(NULL, line, n, opts, error_out); 384 384 err = 0; 385 385 } 386 + *error_out = "configured as 'none'"; 386 387 } else { 387 388 char *new = kstrdup(init, GFP_KERNEL); 388 389 if (!new) { ··· 407 406 } 408 407 } 409 408 if (err) { 409 + *error_out = "failed to parse channel pair"; 410 410 line->init_str = NULL; 411 411 line->valid = 0; 412 412 kfree(new);
-113
arch/um/drivers/pcap_kern.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 - */ 5 - 6 - #include <linux/init.h> 7 - #include <linux/netdevice.h> 8 - #include <net_kern.h> 9 - #include "pcap_user.h" 10 - 11 - struct pcap_init { 12 - char *host_if; 13 - int promisc; 14 - int optimize; 15 - char *filter; 16 - }; 17 - 18 - static void pcap_init_kern(struct net_device *dev, void *data) 19 - { 20 - struct uml_net_private *pri; 21 - struct pcap_data *ppri; 22 - struct pcap_init *init = data; 23 - 24 - pri = netdev_priv(dev); 25 - ppri = (struct pcap_data *) pri->user; 26 - ppri->host_if = init->host_if; 27 - ppri->promisc = init->promisc; 28 - ppri->optimize = init->optimize; 29 - ppri->filter = init->filter; 30 - 31 - printk("pcap backend, host interface %s\n", ppri->host_if); 32 - } 33 - 34 - static int pcap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) 35 - { 36 - return pcap_user_read(fd, skb_mac_header(skb), 37 - skb->dev->mtu + ETH_HEADER_OTHER, 38 - (struct pcap_data *) &lp->user); 39 - } 40 - 41 - static int pcap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) 42 - { 43 - return -EPERM; 44 - } 45 - 46 - static const struct net_kern_info pcap_kern_info = { 47 - .init = pcap_init_kern, 48 - .protocol = eth_protocol, 49 - .read = pcap_read, 50 - .write = pcap_write, 51 - }; 52 - 53 - static int pcap_setup(char *str, char **mac_out, void *data) 54 - { 55 - struct pcap_init *init = data; 56 - char *remain, *host_if = NULL, *options[2] = { NULL, NULL }; 57 - int i; 58 - 59 - *init = ((struct pcap_init) 60 - { .host_if = "eth0", 61 - .promisc = 1, 62 - .optimize = 0, 63 - .filter = NULL }); 64 - 65 - remain = split_if_spec(str, &host_if, &init->filter, 66 - &options[0], &options[1], mac_out, NULL); 67 - if (remain != NULL) { 68 - printk(KERN_ERR "pcap_setup - Extra garbage on " 69 - "specification : '%s'\n", remain); 70 - return 0; 71 - } 72 - 73 - if (host_if != NULL) 74 - init->host_if = host_if; 75 - 76 - for (i = 0; i < ARRAY_SIZE(options); i++) { 77 - if (options[i] == NULL) 78 - continue; 79 - if (!strcmp(options[i], "promisc")) 80 - init->promisc = 1; 81 - else if (!strcmp(options[i], "nopromisc")) 82 - init->promisc = 0; 83 - else if (!strcmp(options[i], "optimize")) 84 - init->optimize = 1; 85 - else if (!strcmp(options[i], "nooptimize")) 86 - init->optimize = 0; 87 - else { 88 - printk(KERN_ERR "pcap_setup : bad option - '%s'\n", 89 - options[i]); 90 - return 0; 91 - } 92 - } 93 - 94 - return 1; 95 - } 96 - 97 - static struct transport pcap_transport = { 98 - .list = LIST_HEAD_INIT(pcap_transport.list), 99 - .name = "pcap", 100 - .setup = pcap_setup, 101 - .user = &pcap_user_info, 102 - .kern = &pcap_kern_info, 103 - .private_size = sizeof(struct pcap_data), 104 - .setup_size = sizeof(struct pcap_init), 105 - }; 106 - 107 - static int register_pcap(void) 108 - { 109 - register_transport(&pcap_transport); 110 - return 0; 111 - } 112 - 113 - late_initcall(register_pcap);
-137
arch/um/drivers/pcap_user.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 - */ 5 - 6 - #include <errno.h> 7 - #include <pcap.h> 8 - #include <string.h> 9 - #include <asm/types.h> 10 - #include <net_user.h> 11 - #include "pcap_user.h" 12 - #include <um_malloc.h> 13 - 14 - #define PCAP_FD(p) (*(int *)(p)) 15 - 16 - static int pcap_user_init(void *data, void *dev) 17 - { 18 - struct pcap_data *pri = data; 19 - pcap_t *p; 20 - char errors[PCAP_ERRBUF_SIZE]; 21 - 22 - p = pcap_open_live(pri->host_if, ETH_MAX_PACKET + ETH_HEADER_OTHER, 23 - pri->promisc, 0, errors); 24 - if (p == NULL) { 25 - printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - " 26 - "'%s'\n", errors); 27 - return -EINVAL; 28 - } 29 - 30 - pri->dev = dev; 31 - pri->pcap = p; 32 - return 0; 33 - } 34 - 35 - static int pcap_user_open(void *data) 36 - { 37 - struct pcap_data *pri = data; 38 - __u32 netmask; 39 - int err; 40 - 41 - if (pri->pcap == NULL) 42 - return -ENODEV; 43 - 44 - if (pri->filter != NULL) { 45 - err = dev_netmask(pri->dev, &netmask); 46 - if (err < 0) { 47 - printk(UM_KERN_ERR "pcap_user_open : dev_netmask failed\n"); 48 - return -EIO; 49 - } 50 - 51 - pri->compiled = uml_kmalloc(sizeof(struct bpf_program), 52 - UM_GFP_KERNEL); 53 - if (pri->compiled == NULL) { 54 - printk(UM_KERN_ERR "pcap_user_open : kmalloc failed\n"); 55 - return -ENOMEM; 56 - } 57 - 58 - err = pcap_compile(pri->pcap, 59 - (struct bpf_program *) pri->compiled, 60 - pri->filter, pri->optimize, netmask); 61 - if (err < 0) { 62 - printk(UM_KERN_ERR "pcap_user_open : pcap_compile failed - " 63 - "'%s'\n", pcap_geterr(pri->pcap)); 64 - goto out; 65 - } 66 - 67 - err = pcap_setfilter(pri->pcap, pri->compiled); 68 - if (err < 0) { 69 - printk(UM_KERN_ERR "pcap_user_open : pcap_setfilter " 70 - "failed - '%s'\n", pcap_geterr(pri->pcap)); 71 - goto out; 72 - } 73 - } 74 - 75 - return PCAP_FD(pri->pcap); 76 - 77 - out: 78 - kfree(pri->compiled); 79 - return -EIO; 80 - } 81 - 82 - static void pcap_remove(void *data) 83 - { 84 - struct pcap_data *pri = data; 85 - 86 - if (pri->compiled != NULL) 87 - pcap_freecode(pri->compiled); 88 - 89 - if (pri->pcap != NULL) 90 - pcap_close(pri->pcap); 91 - } 92 - 93 - struct pcap_handler_data { 94 - char *buffer; 95 - int len; 96 - }; 97 - 98 - static void handler(u_char *data, const struct pcap_pkthdr *header, 99 - const u_char *packet) 100 - { 101 - int len; 102 - 103 - struct pcap_handler_data *hdata = (struct pcap_handler_data *) data; 104 - 105 - len = hdata->len < header->caplen ? hdata->len : header->caplen; 106 - memcpy(hdata->buffer, packet, len); 107 - hdata->len = len; 108 - } 109 - 110 - int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri) 111 - { 112 - struct pcap_handler_data hdata = ((struct pcap_handler_data) 113 - { .buffer = buffer, 114 - .len = len }); 115 - int n; 116 - 117 - n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata); 118 - if (n < 0) { 119 - printk(UM_KERN_ERR "pcap_dispatch failed - %s\n", 120 - pcap_geterr(pri->pcap)); 121 - return -EIO; 122 - } 123 - else if (n == 0) 124 - return 0; 125 - return hdata.len; 126 - } 127 - 128 - const struct net_user_info pcap_user_info = { 129 - .init = pcap_user_init, 130 - .open = pcap_user_open, 131 - .close = NULL, 132 - .remove = pcap_remove, 133 - .add_address = NULL, 134 - .delete_address = NULL, 135 - .mtu = ETH_MAX_PACKET, 136 - .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, 137 - };
-21
arch/um/drivers/pcap_user.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* 3 - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 4 - */ 5 - 6 - #include <net_user.h> 7 - 8 - struct pcap_data { 9 - char *host_if; 10 - int promisc; 11 - int optimize; 12 - char *filter; 13 - void *compiled; 14 - void *pcap; 15 - void *dev; 16 - }; 17 - 18 - extern const struct net_user_info pcap_user_info; 19 - 20 - extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); 21 -
+8 -6
arch/um/drivers/port_kern.c
··· 45 45 static irqreturn_t pipe_interrupt(int irq, void *data) 46 46 { 47 47 struct connection *conn = data; 48 - int fd; 48 + int n_fds = 1, fd = -1; 49 + ssize_t ret; 49 50 50 - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); 51 - if (fd < 0) { 52 - if (fd == -EAGAIN) 51 + ret = os_rcv_fd_msg(conn->socket[0], &fd, n_fds, &conn->helper_pid, 52 + sizeof(conn->helper_pid)); 53 + if (ret != sizeof(conn->helper_pid)) { 54 + if (ret == -EAGAIN) 53 55 return IRQ_NONE; 54 56 55 - printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", 56 - -fd); 57 + printk(KERN_ERR "pipe_interrupt : os_rcv_fd_msg returned %zd\n", 58 + ret); 57 59 os_close_file(conn->fd); 58 60 } 59 61
-3
arch/um/drivers/ubd_kern.c
··· 36 36 #include <linux/vmalloc.h> 37 37 #include <linux/platform_device.h> 38 38 #include <linux/scatterlist.h> 39 - #include <asm/tlbflush.h> 40 39 #include <kern_util.h> 41 40 #include "mconsole_kern.h" 42 41 #include <init.h> ··· 105 106 #define DRIVER_NAME "uml-blkdev" 106 107 107 108 static DEFINE_MUTEX(ubd_lock); 108 - static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */ 109 109 110 110 static int ubd_ioctl(struct block_device *bdev, blk_mode_t mode, 111 111 unsigned int cmd, unsigned long arg); ··· 757 759 printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); 758 760 goto error; 759 761 } 760 - flush_tlb_kernel_vm(); 761 762 762 763 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap, 763 764 ubd_dev->cow.bitmap_offset,
+3 -16
arch/um/drivers/vector_kern.c
··· 1115 1115 static int vector_net_close(struct net_device *dev) 1116 1116 { 1117 1117 struct vector_private *vp = netdev_priv(dev); 1118 - unsigned long flags; 1119 1118 1120 1119 netif_stop_queue(dev); 1121 1120 del_timer(&vp->tl); 1121 + 1122 + vp->opened = false; 1122 1123 1123 1124 if (vp->fds == NULL) 1124 1125 return 0; ··· 1159 1158 destroy_queue(vp->tx_queue); 1160 1159 kfree(vp->fds); 1161 1160 vp->fds = NULL; 1162 - spin_lock_irqsave(&vp->lock, flags); 1163 - vp->opened = false; 1164 1161 vp->in_error = false; 1165 - spin_unlock_irqrestore(&vp->lock, flags); 1166 1162 return 0; 1167 1163 } 1168 1164 ··· 1201 1203 static int vector_net_open(struct net_device *dev) 1202 1204 { 1203 1205 struct vector_private *vp = netdev_priv(dev); 1204 - unsigned long flags; 1205 1206 int err = -EINVAL; 1206 1207 struct vector_device *vdevice; 1207 1208 1208 - spin_lock_irqsave(&vp->lock, flags); 1209 - if (vp->opened) { 1210 - spin_unlock_irqrestore(&vp->lock, flags); 1209 + if (vp->opened) 1211 1210 return -ENXIO; 1212 - } 1213 1211 vp->opened = true; 1214 - spin_unlock_irqrestore(&vp->lock, flags); 1215 1212 1216 1213 vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed)); 1217 1214 ··· 1380 1387 return -1; 1381 1388 } 1382 1389 1383 - spin_lock(&vp->lock); 1384 - 1385 1390 if (vp->bpf != NULL) { 1386 1391 if (vp->opened) 1387 1392 uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); ··· 1408 1417 if (vp->opened) 1409 1418 result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); 1410 1419 1411 - spin_unlock(&vp->lock); 1412 - 1413 1420 return result; 1414 1421 1415 1422 free_buffer: 1416 1423 release_firmware(fw); 1417 1424 1418 1425 flash_fail: 1419 - spin_unlock(&vp->lock); 1420 1426 if (vp->bpf != NULL) 1421 1427 kfree(vp->bpf->filter); 1422 1428 kfree(vp->bpf); ··· 1619 1631 INIT_WORK(&vp->reset_tx, vector_reset_tx); 1620 1632 1621 1633 timer_setup(&vp->tl, vector_timer_expire, 0); 1622 - spin_lock_init(&vp->lock); 1623 1634 1624 1635 /* FIXME */ 1625 1636 dev->netdev_ops = &vector_netdev_ops;
-1
arch/um/drivers/vector_kern.h
··· 71 71 72 72 struct vector_private { 73 73 struct list_head list; 74 - spinlock_t lock; 75 74 struct net_device *dev; 76 75 struct napi_struct napi ____cacheline_aligned; 77 76
+1 -1
arch/um/drivers/xterm.c
··· 156 156 new = xterm_fd(fd, &data->helper_pid); 157 157 if (new < 0) { 158 158 err = new; 159 - printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n", 159 + printk(UM_KERN_ERR "xterm_open : xterm_fd failed, err = %d\n", 160 160 -err); 161 161 goto out_kill; 162 162 }
+10 -3
arch/um/drivers/xterm_kern.c
··· 21 21 static irqreturn_t xterm_interrupt(int irq, void *data) 22 22 { 23 23 struct xterm_wait *xterm = data; 24 - int fd; 24 + int fd = -1, n_fds = 1; 25 + ssize_t ret; 25 26 26 - fd = os_rcv_fd(xterm->fd, &xterm->pid); 27 - if (fd == -EAGAIN) 27 + ret = os_rcv_fd_msg(xterm->fd, &fd, n_fds, 28 + &xterm->pid, sizeof(xterm->pid)); 29 + if (ret == -EAGAIN) 28 30 return IRQ_NONE; 31 + 32 + if (ret < 0) 33 + fd = ret; 34 + else if (ret != sizeof(xterm->pid)) 35 + fd = -EMSGSIZE; 29 36 30 37 xterm->new_fd = fd; 31 38 complete(&xterm->ready);
+4 -6
arch/um/include/asm/mmu.h
··· 7 7 #define __ARCH_UM_MMU_H 8 8 9 9 #include <mm_id.h> 10 - #include <asm/mm_context.h> 11 10 12 11 typedef struct mm_context { 13 12 struct mm_id id; 14 - struct uml_arch_mm_context arch; 15 - } mm_context_t; 16 13 17 - /* Avoid tangled inclusion with asm/ldt.h */ 18 - extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); 19 - extern void free_ldt(struct mm_context *mm); 14 + /* Address range in need of a TLB sync */ 15 + unsigned long sync_tlb_range_from; 16 + unsigned long sync_tlb_range_to; 17 + } mm_context_t; 20 18 21 19 #endif
-2
arch/um/include/asm/mmu_context.h
··· 13 13 #include <asm/mm_hooks.h> 14 14 #include <asm/mmu.h> 15 15 16 - extern void force_flush_all(void); 17 - 18 16 #define activate_mm activate_mm 19 17 static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) 20 18 {
+32
arch/um/include/asm/pgtable.h
··· 244 244 245 245 #define PFN_PTE_SHIFT PAGE_SHIFT 246 246 247 + static inline void um_tlb_mark_sync(struct mm_struct *mm, unsigned long start, 248 + unsigned long end) 249 + { 250 + if (!mm->context.sync_tlb_range_to) { 251 + mm->context.sync_tlb_range_from = start; 252 + mm->context.sync_tlb_range_to = end; 253 + } else { 254 + if (start < mm->context.sync_tlb_range_from) 255 + mm->context.sync_tlb_range_from = start; 256 + if (end > mm->context.sync_tlb_range_to) 257 + mm->context.sync_tlb_range_to = end; 258 + } 259 + } 260 + 261 + #define set_ptes set_ptes 262 + static inline void set_ptes(struct mm_struct *mm, unsigned long addr, 263 + pte_t *ptep, pte_t pte, int nr) 264 + { 265 + /* Basically the default implementation */ 266 + size_t length = nr * PAGE_SIZE; 267 + 268 + for (;;) { 269 + set_pte(ptep, pte); 270 + if (--nr == 0) 271 + break; 272 + ptep++; 273 + pte = __pte(pte_val(pte) + (nr << PFN_PTE_SHIFT)); 274 + } 275 + 276 + um_tlb_mark_sync(mm, addr, addr + length); 277 + } 278 + 247 279 #define __HAVE_ARCH_PTE_SAME 248 280 static inline int pte_same(pte_t pte_a, pte_t pte_b) 249 281 {
+37 -9
arch/um/include/asm/tlbflush.h
··· 9 9 #include <linux/mm.h> 10 10 11 11 /* 12 - * TLB flushing: 12 + * In UML, we need to sync the TLB over by using mmap/munmap/mprotect syscalls 13 + * from the process handling the MM (which can be the kernel itself). 13 14 * 14 - * - flush_tlb() flushes the current mm struct TLBs 15 + * To track updates, we can hook into set_ptes and flush_tlb_*. With set_ptes 16 + * we catch all PTE transitions where memory that was unusable becomes usable. 17 + * While with flush_tlb_* we can track any memory that becomes unusable and 18 + * even if a higher layer of the page table was modified. 19 + * 20 + * So, we simply track updates using both methods and mark the memory area to 21 + * be synced later on. The only special case is that flush_tlb_kern_* needs to 22 + * be executed immediately as there is no good synchronization point in that 23 + * case. In contrast, in the set_ptes case we can wait for the next kernel 24 + * segfault before we do the synchornization. 25 + * 15 26 * - flush_tlb_all() flushes all processes TLBs 16 27 * - flush_tlb_mm(mm) flushes the specified mm context TLB's 17 28 * - flush_tlb_page(vma, vmaddr) flushes one page 18 - * - flush_tlb_kernel_vm() flushes the kernel vm area 19 29 * - flush_tlb_range(vma, start, end) flushes a range of pages 30 + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages 20 31 */ 32 + 33 + extern int um_tlb_sync(struct mm_struct *mm); 21 34 22 35 extern void flush_tlb_all(void); 23 36 extern void flush_tlb_mm(struct mm_struct *mm); 24 - extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 25 - unsigned long end); 26 - extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long address); 27 - extern void flush_tlb_kernel_vm(void); 28 - extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); 29 - extern void __flush_tlb_one(unsigned long addr); 37 + 38 + static inline void flush_tlb_page(struct vm_area_struct *vma, 39 + unsigned long address) 40 + { 41 + um_tlb_mark_sync(vma->vm_mm, address, address + PAGE_SIZE); 42 + } 43 + 44 + static inline void flush_tlb_range(struct vm_area_struct *vma, 45 + unsigned long start, unsigned long end) 46 + { 47 + um_tlb_mark_sync(vma->vm_mm, start, end); 48 + } 49 + 50 + static inline void flush_tlb_kernel_range(unsigned long start, 51 + unsigned long end) 52 + { 53 + um_tlb_mark_sync(&init_mm, start, end); 54 + 55 + /* Kernel needs to be synced immediately */ 56 + um_tlb_sync(&init_mm); 57 + } 30 58 31 59 #endif
+1 -1
arch/um/include/shared/as-layout.h
··· 23 23 #define STUB_START stub_start 24 24 #define STUB_CODE STUB_START 25 25 #define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE) 26 - #define STUB_DATA_PAGES 1 /* must be a power of two */ 26 + #define STUB_DATA_PAGES 2 /* must be a power of two */ 27 27 #define STUB_END (STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE) 28 28 29 29 #ifndef __ASSEMBLY__
-5
arch/um/include/shared/common-offsets.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* for use by sys-$SUBARCH/kernel-offsets.c */ 3 - #include <stub-data.h> 4 3 5 4 DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); 6 5 ··· 29 30 DEFINE(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT, CONFIG_UML_TIME_TRAVEL_SUPPORT); 30 31 #endif 31 32 32 - /* for stub */ 33 - DEFINE(UML_STUB_FIELD_OFFSET, offsetof(struct stub_data, offset)); 34 - DEFINE(UML_STUB_FIELD_CHILD_ERR, offsetof(struct stub_data, child_err)); 35 - DEFINE(UML_STUB_FIELD_FD, offsetof(struct stub_data, fd));
-1
arch/um/include/shared/kern_util.h
··· 13 13 14 14 extern int uml_exitcode; 15 15 16 - extern int ncpus; 17 16 extern int kmalloc_ok; 18 17 19 18 #define UML_ROUND_UP(addr) \
+18 -15
arch/um/include/shared/os.h
··· 163 163 extern int os_accept_connection(int fd); 164 164 extern int os_create_unix_socket(const char *file, int len, int close_on_exec); 165 165 extern int os_shutdown_socket(int fd, int r, int w); 166 + extern int os_dup_file(int fd); 166 167 extern void os_close_file(int fd); 167 - extern int os_rcv_fd(int fd, int *helper_pid_out); 168 + ssize_t os_rcv_fd_msg(int fd, int *fds, unsigned int n_fds, 169 + void *data, size_t data_len); 168 170 extern int os_connect_socket(const char *name); 169 171 extern int os_file_type(char *file); 170 172 extern int os_file_mode(const char *file, struct openflags *mode_out); ··· 181 179 extern int os_sendmsg_fds(int fd, const void *buf, unsigned int len, 182 180 const int *fds, unsigned int fds_num); 183 181 int os_poll(unsigned int n, const int *fds); 182 + void *os_mmap_rw_shared(int fd, size_t size); 183 + void *os_mremap_rw_shared(void *old_addr, size_t old_size, size_t new_size); 184 184 185 185 /* start_up.c */ 186 186 extern void os_early_checks(void); ··· 194 190 195 191 /* mem.c */ 196 192 extern int create_mem_file(unsigned long long len); 193 + 194 + /* tlb.c */ 195 + extern void report_enomem(void); 197 196 198 197 /* process.c */ 199 198 extern unsigned long os_process_pc(int pid); ··· 275 268 extern long long os_nsecs(void); 276 269 277 270 /* skas/mem.c */ 278 - extern long run_syscall_stub(struct mm_id * mm_idp, 279 - int syscall, unsigned long *args, long expected, 280 - void **addr, int done); 281 - extern long syscall_stub_data(struct mm_id * mm_idp, 282 - unsigned long *data, int data_count, 283 - void **addr, void **stub_addr); 284 - extern int map(struct mm_id * mm_idp, unsigned long virt, 285 - unsigned long len, int prot, int phys_fd, 286 - unsigned long long offset, int done, void **data); 287 - extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 288 - int done, void **data); 289 - extern int protect(struct mm_id * mm_idp, unsigned long addr, 290 - unsigned long len, unsigned int prot, int done, void **data); 271 + int syscall_stub_flush(struct mm_id *mm_idp); 272 + struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp); 273 + void syscall_stub_dump_error(struct mm_id *mm_idp); 274 + 275 + int map(struct mm_id *mm_idp, unsigned long virt, 276 + unsigned long len, int prot, int phys_fd, 277 + unsigned long long offset); 278 + int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len); 279 + int protect(struct mm_id *mm_idp, unsigned long addr, 280 + unsigned long len, unsigned int prot); 291 281 292 282 /* skas/process.c */ 293 283 extern int is_skas_winch(int pid, int fd, void *data); 294 284 extern int start_userspace(unsigned long stub_stack); 295 - extern int copy_context_skas0(unsigned long stack, int pid); 296 285 extern void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs); 297 286 extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); 298 287 extern void switch_threads(jmp_buf *me, jmp_buf *you);
+1 -1
arch/um/include/shared/skas/mm_id.h
··· 12 12 int pid; 13 13 } u; 14 14 unsigned long stack; 15 - int kill; 15 + int syscall_data_len; 16 16 }; 17 17 18 18 void __switch_mm(struct mm_id *mm_idp);
+2
arch/um/include/shared/skas/skas.h
··· 15 15 extern void handle_syscall(struct uml_pt_regs *regs); 16 16 extern long execute_syscall_skas(void *r); 17 17 extern unsigned long current_stub_stack(void); 18 + extern struct mm_id *current_mm_id(void); 19 + extern void current_mm_sync(void); 18 20 19 21 #endif
+34 -2
arch/um/include/shared/skas/stub-data.h
··· 8 8 #ifndef __STUB_DATA_H 9 9 #define __STUB_DATA_H 10 10 11 + #include <linux/compiler_types.h> 12 + #include <as-layout.h> 13 + #include <sysdep/tls.h> 14 + 15 + #define STUB_NEXT_SYSCALL(s) \ 16 + ((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len)) 17 + 18 + enum stub_syscall_type { 19 + STUB_SYSCALL_UNSET = 0, 20 + STUB_SYSCALL_MMAP, 21 + STUB_SYSCALL_MUNMAP, 22 + STUB_SYSCALL_MPROTECT, 23 + }; 24 + 25 + struct stub_syscall { 26 + struct { 27 + unsigned long addr; 28 + unsigned long length; 29 + unsigned long offset; 30 + int fd; 31 + int prot; 32 + } mem; 33 + 34 + enum stub_syscall_type syscall; 35 + }; 36 + 11 37 struct stub_data { 12 38 unsigned long offset; 13 - int fd; 14 - long parent_err, child_err; 39 + long err, child_err; 40 + 41 + int syscall_data_len; 42 + /* 128 leaves enough room for additional fields in the struct */ 43 + struct stub_syscall syscall_data[(UM_KERN_PAGE_SIZE - 128) / sizeof(struct stub_syscall)] __aligned(16); 44 + 45 + /* Stack for our signal handlers and for calling into . */ 46 + unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE); 15 47 }; 16 48 17 49 #endif
+9
arch/um/include/shared/timetravel.h
··· 15 15 #if defined(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT) || \ 16 16 defined(CONFIG_UML_TIME_TRAVEL_SUPPORT) 17 17 extern enum time_travel_mode time_travel_mode; 18 + extern int time_travel_should_print_bc_msg; 18 19 #else 19 20 #define time_travel_mode TT_MODE_OFF 21 + #define time_travel_should_print_bc_msg 0 20 22 #endif /* (UML_)CONFIG_UML_TIME_TRAVEL_SUPPORT */ 23 + 24 + void _time_travel_print_bc_msg(void); 25 + static inline void time_travel_print_bc_msg(void) 26 + { 27 + if (time_travel_should_print_bc_msg) 28 + _time_travel_print_bc_msg(); 29 + } 21 30 22 31 #endif /* _UM_TIME_TRAVEL_H_ */
+8
arch/um/include/shared/user.h
··· 42 42 #define printk(...) _printk(__VA_ARGS__) 43 43 extern int _printk(const char *fmt, ...) 44 44 __attribute__ ((format (printf, 1, 2))); 45 + extern void print_hex_dump(const char *level, const char *prefix_str, 46 + int prefix_type, int rowsize, int groupsize, 47 + const void *buf, size_t len, _Bool ascii); 45 48 #else 46 49 static inline int printk(const char *fmt, ...) 47 50 { 48 51 return 0; 52 + } 53 + static inline void print_hex_dump(const char *level, const char *prefix_str, 54 + int prefix_type, int rowsize, int groupsize, 55 + const void *buf, size_t len, _Bool ascii) 56 + { 49 57 } 50 58 #endif 51 59
-9
arch/um/kernel/exec.c
··· 22 22 23 23 void flush_thread(void) 24 24 { 25 - void *data = NULL; 26 - int ret; 27 - 28 25 arch_flush_thread(&current->thread.arch); 29 26 30 - ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data); 31 - if (ret) { 32 - printk(KERN_ERR "%s - clearing address space failed, err = %d\n", 33 - __func__, ret); 34 - force_sig(SIGKILL); 35 - } 36 27 get_safe_registers(current_pt_regs()->regs.gp, 37 28 current_pt_regs()->regs.fp); 38 29
+51 -29
arch/um/kernel/irq.c
··· 37 37 bool pending; 38 38 bool wakeup; 39 39 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 40 - bool pending_on_resume; 40 + bool pending_event; 41 41 void (*timetravel_handler)(int, int, void *, 42 42 struct time_travel_event *); 43 43 struct time_travel_event event; ··· 56 56 static LIST_HEAD(active_fds); 57 57 static DECLARE_BITMAP(irqs_allocated, UM_LAST_SIGNAL_IRQ); 58 58 static bool irqs_suspended; 59 + #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 60 + static bool irqs_pending; 61 + #endif 59 62 60 63 static void irq_io_loop(struct irq_reg *irq, struct uml_pt_regs *regs) 61 64 { ··· 87 84 { 88 85 struct irq_reg *reg = container_of(ev, struct irq_reg, event); 89 86 90 - /* do nothing if suspended - just to cause a wakeup */ 91 - if (irqs_suspended) 87 + /* do nothing if suspended; just cause a wakeup and mark as pending */ 88 + if (irqs_suspended) { 89 + irqs_pending = true; 90 + reg->pending_event = true; 92 91 return; 92 + } 93 93 94 94 generic_handle_irq(reg->irq); 95 95 } ··· 116 110 if (!reg->event.pending) 117 111 return false; 118 112 119 - if (irqs_suspended) 120 - reg->pending_on_resume = true; 121 113 return true; 114 + } 115 + 116 + static void irq_do_pending_events(bool timetravel_handlers_only) 117 + { 118 + struct irq_entry *entry; 119 + 120 + if (!irqs_pending || timetravel_handlers_only) 121 + return; 122 + 123 + irqs_pending = false; 124 + 125 + list_for_each_entry(entry, &active_fds, list) { 126 + enum um_irq_type t; 127 + 128 + for (t = 0; t < NUM_IRQ_TYPES; t++) { 129 + struct irq_reg *reg = &entry->reg[t]; 130 + 131 + /* 132 + * Any timetravel_handler was invoked already, just 133 + * directly run the IRQ. 134 + */ 135 + if (reg->pending_event) { 136 + irq_enter(); 137 + generic_handle_irq(reg->irq); 138 + irq_exit(); 139 + reg->pending_event = false; 140 + } 141 + } 142 + } 122 143 } 123 144 #else 124 145 static bool irq_do_timetravel_handler(struct irq_entry *entry, 125 146 enum um_irq_type t) 126 147 { 127 148 return false; 149 + } 150 + 151 + static void irq_do_pending_events(bool timetravel_handlers_only) 152 + { 128 153 } 129 154 #endif 130 155 ··· 182 145 */ 183 146 if (timetravel_handlers_only) { 184 147 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 148 + reg->pending_event = true; 149 + irqs_pending = true; 185 150 mark_sigio_pending(); 186 151 #endif 187 152 return; ··· 200 161 201 162 if (timetravel_handlers_only && !um_irq_timetravel_handler_used()) 202 163 return; 164 + 165 + /* Flush out pending events that were ignored due to time-travel. */ 166 + if (!irqs_suspended) 167 + irq_do_pending_events(timetravel_handlers_only); 203 168 204 169 while (1) { 205 170 /* This is now lockless - epoll keeps back-referencesto the irqs ··· 238 195 239 196 void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 240 197 { 198 + preempt_disable(); 241 199 _sigio_handler(regs, irqs_suspended); 200 + preempt_enable(); 242 201 } 243 202 244 203 static struct irq_entry *get_irq_entry_by_fd(int fd) ··· 588 543 unsigned long flags; 589 544 590 545 591 - local_irq_save(flags); 592 - #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 593 - /* 594 - * We don't need to lock anything here since we're in resume 595 - * and nothing else is running, but have disabled IRQs so we 596 - * don't try anything else with the interrupt list from there. 597 - */ 598 - list_for_each_entry(entry, &active_fds, list) { 599 - enum um_irq_type t; 600 - 601 - for (t = 0; t < NUM_IRQ_TYPES; t++) { 602 - struct irq_reg *reg = &entry->reg[t]; 603 - 604 - if (reg->pending_on_resume) { 605 - irq_enter(); 606 - generic_handle_irq(reg->irq); 607 - irq_exit(); 608 - reg->pending_on_resume = false; 609 - } 610 - } 611 - } 612 - #endif 613 - 614 - spin_lock(&irq_lock); 546 + spin_lock_irqsave(&irq_lock, flags); 615 547 list_for_each_entry(entry, &active_fds, list) { 616 548 if (entry->suspended) { 617 549 int err = os_set_fd_async(entry->fd);
+1 -1
arch/um/kernel/ksyms.c
··· 33 33 EXPORT_SYMBOL(os_create_unix_socket); 34 34 EXPORT_SYMBOL(os_connect_socket); 35 35 EXPORT_SYMBOL(os_accept_connection); 36 - EXPORT_SYMBOL(os_rcv_fd); 36 + EXPORT_SYMBOL(os_rcv_fd_msg); 37 37 EXPORT_SYMBOL(run_helper); 38 38 EXPORT_SYMBOL(os_major); 39 39 EXPORT_SYMBOL(os_minor);
-1
arch/um/kernel/mem.c
··· 73 73 74 74 /* this will put all low memory onto the freelists */ 75 75 memblock_free_all(); 76 - max_low_pfn = totalram_pages(); 77 76 max_pfn = max_low_pfn; 78 77 kmalloc_ok = 1; 79 78 }
-69
arch/um/kernel/process.c
··· 122 122 /* Called magically, see new_thread_handler above */ 123 123 static void fork_handler(void) 124 124 { 125 - force_flush_all(); 126 - 127 125 schedule_tail(current->thread.prev_sched); 128 126 129 127 /* ··· 234 236 { 235 237 return copy_from_user(to, from, size); 236 238 } 237 - 238 - static atomic_t using_sysemu = ATOMIC_INIT(0); 239 - int sysemu_supported; 240 - 241 - static void set_using_sysemu(int value) 242 - { 243 - if (value > sysemu_supported) 244 - return; 245 - atomic_set(&using_sysemu, value); 246 - } 247 - 248 - static int get_using_sysemu(void) 249 - { 250 - return atomic_read(&using_sysemu); 251 - } 252 - 253 - static int sysemu_proc_show(struct seq_file *m, void *v) 254 - { 255 - seq_printf(m, "%d\n", get_using_sysemu()); 256 - return 0; 257 - } 258 - 259 - static int sysemu_proc_open(struct inode *inode, struct file *file) 260 - { 261 - return single_open(file, sysemu_proc_show, NULL); 262 - } 263 - 264 - static ssize_t sysemu_proc_write(struct file *file, const char __user *buf, 265 - size_t count, loff_t *pos) 266 - { 267 - char tmp[2]; 268 - 269 - if (copy_from_user(tmp, buf, 1)) 270 - return -EFAULT; 271 - 272 - if (tmp[0] >= '0' && tmp[0] <= '2') 273 - set_using_sysemu(tmp[0] - '0'); 274 - /* We use the first char, but pretend to write everything */ 275 - return count; 276 - } 277 - 278 - static const struct proc_ops sysemu_proc_ops = { 279 - .proc_open = sysemu_proc_open, 280 - .proc_read = seq_read, 281 - .proc_lseek = seq_lseek, 282 - .proc_release = single_release, 283 - .proc_write = sysemu_proc_write, 284 - }; 285 - 286 - static int __init make_proc_sysemu(void) 287 - { 288 - struct proc_dir_entry *ent; 289 - if (!sysemu_supported) 290 - return 0; 291 - 292 - ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_ops); 293 - 294 - if (ent == NULL) 295 - { 296 - printk(KERN_WARNING "Failed to register /proc/sysemu\n"); 297 - return 0; 298 - } 299 - 300 - return 0; 301 - } 302 - 303 - late_initcall(make_proc_sysemu); 304 239 305 240 int singlestepping(void) 306 241 {
+15
arch/um/kernel/reboot.c
··· 59 59 { 60 60 machine_power_off(); 61 61 } 62 + 63 + static int sys_power_off_handler(struct sys_off_data *data) 64 + { 65 + machine_power_off(); 66 + return 0; 67 + } 68 + 69 + static int register_power_off(void) 70 + { 71 + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, 72 + SYS_OFF_PRIO_DEFAULT, 73 + sys_power_off_handler, NULL); 74 + return 0; 75 + } 76 + __initcall(register_power_off);
+4 -5
arch/um/kernel/skas/Makefile
··· 3 3 # Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 4 # 5 5 6 - obj-y := clone.o mmu.o process.o syscall.o uaccess.o 6 + obj-y := stub.o mmu.o process.o syscall.o uaccess.o 7 7 8 - # clone.o is in the stub, so it can't be built with profiling 8 + # stub.o is in the stub, so it can't be built with profiling 9 9 # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> 10 10 # disable it 11 11 12 - CFLAGS_clone.o := $(CFLAGS_NO_HARDENING) 13 - UNPROFILE_OBJS := clone.o 14 - 12 + CFLAGS_stub.o := $(CFLAGS_NO_HARDENING) 13 + UNPROFILE_OBJS := stub.o 15 14 KCOV_INSTRUMENT := n 16 15 17 16 include $(srctree)/arch/um/scripts/Makefile.rules
-48
arch/um/kernel/skas/clone.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 4 - * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 5 - */ 6 - 7 - #include <signal.h> 8 - #include <sched.h> 9 - #include <asm/unistd.h> 10 - #include <sys/time.h> 11 - #include <as-layout.h> 12 - #include <ptrace_user.h> 13 - #include <stub-data.h> 14 - #include <sysdep/stub.h> 15 - 16 - /* 17 - * This is in a separate file because it needs to be compiled with any 18 - * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled 19 - * 20 - * Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize 21 - * on some systems. 22 - */ 23 - 24 - void __attribute__ ((__section__ (".__syscall_stub"))) 25 - stub_clone_handler(void) 26 - { 27 - struct stub_data *data = get_stub_data(); 28 - long err; 29 - 30 - err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, 31 - (unsigned long)data + 32 - STUB_DATA_PAGES * UM_KERN_PAGE_SIZE / 2); 33 - if (err) { 34 - data->parent_err = err; 35 - goto done; 36 - } 37 - 38 - err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); 39 - if (err) { 40 - data->child_err = err; 41 - goto done; 42 - } 43 - 44 - remap_stack_and_trap(); 45 - 46 - done: 47 - trap_myself(); 48 - }
+34 -20
arch/um/kernel/skas/mmu.c
··· 14 14 #include <as-layout.h> 15 15 #include <os.h> 16 16 #include <skas.h> 17 + #include <stub-data.h> 18 + 19 + /* Ensure the stub_data struct covers the allocated area */ 20 + static_assert(sizeof(struct stub_data) == STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); 17 21 18 22 int init_new_context(struct task_struct *task, struct mm_struct *mm) 19 23 { 20 - struct mm_context *from_mm = NULL; 21 - struct mm_context *to_mm = &mm->context; 24 + struct mm_id *new_id = &mm->context.id; 22 25 unsigned long stack = 0; 23 26 int ret = -ENOMEM; 24 27 ··· 29 26 if (stack == 0) 30 27 goto out; 31 28 32 - to_mm->id.stack = stack; 33 - if (current->mm != NULL && current->mm != &init_mm) 34 - from_mm = &current->mm->context; 29 + new_id->stack = stack; 35 30 36 31 block_signals_trace(); 37 - if (from_mm) 38 - to_mm->id.u.pid = copy_context_skas0(stack, 39 - from_mm->id.u.pid); 40 - else to_mm->id.u.pid = start_userspace(stack); 32 + new_id->u.pid = start_userspace(stack); 41 33 unblock_signals_trace(); 42 34 43 - if (to_mm->id.u.pid < 0) { 44 - ret = to_mm->id.u.pid; 35 + if (new_id->u.pid < 0) { 36 + ret = new_id->u.pid; 45 37 goto out_free; 46 38 } 47 39 48 - ret = init_new_ldt(to_mm, from_mm); 49 - if (ret < 0) { 50 - printk(KERN_ERR "init_new_context_skas - init_ldt" 51 - " failed, errno = %d\n", ret); 52 - goto out_free; 53 - } 40 + /* 41 + * Ensure the new MM is clean and nothing unwanted is mapped. 42 + * 43 + * TODO: We should clear the memory up to STUB_START to ensure there is 44 + * nothing mapped there, i.e. we (currently) have: 45 + * 46 + * |- user memory -|- unused -|- stub -|- unused -| 47 + * ^ TASK_SIZE ^ STUB_START 48 + * 49 + * Meaning we have two unused areas where we may still have valid 50 + * mappings from our internal clone(). That isn't really a problem as 51 + * userspace is not going to access them, but it is definitely not 52 + * correct. 53 + * 54 + * However, we are "lucky" and if rseq is configured, then on 32 bit 55 + * it will fall into the first empty range while on 64 bit it is going 56 + * to use an anonymous mapping in the second range. As such, things 57 + * continue to work for now as long as we don't start unmapping these 58 + * areas. 59 + * 60 + * Change this to STUB_START once we have a clean userspace. 61 + */ 62 + unmap(new_id, 0, TASK_SIZE); 54 63 55 64 return 0; 56 65 57 66 out_free: 58 - if (to_mm->id.stack != 0) 59 - free_pages(to_mm->id.stack, ilog2(STUB_DATA_PAGES)); 67 + if (new_id->stack != 0) 68 + free_pages(new_id->stack, ilog2(STUB_DATA_PAGES)); 60 69 out: 61 70 return ret; 62 71 } ··· 91 76 os_kill_ptraced_process(mmu->id.u.pid, 1); 92 77 93 78 free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES)); 94 - free_ldt(mmu); 95 79 }
+18
arch/um/kernel/skas/process.c
··· 8 8 #include <linux/sched/task_stack.h> 9 9 #include <linux/sched/task.h> 10 10 11 + #include <asm/tlbflush.h> 12 + 11 13 #include <as-layout.h> 12 14 #include <kern.h> 13 15 #include <os.h> ··· 51 49 return 0; 52 50 53 51 return current->mm->context.id.stack; 52 + } 53 + 54 + struct mm_id *current_mm_id(void) 55 + { 56 + if (current->mm == NULL) 57 + return NULL; 58 + 59 + return &current->mm->context.id; 60 + } 61 + 62 + void current_mm_sync(void) 63 + { 64 + if (current->mm == NULL) 65 + return; 66 + 67 + um_tlb_sync(current->mm); 54 68 }
+69
arch/um/kernel/skas/stub.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net> 4 + */ 5 + 6 + #include <sysdep/stub.h> 7 + 8 + static __always_inline int syscall_handler(struct stub_data *d) 9 + { 10 + int i; 11 + unsigned long res; 12 + 13 + for (i = 0; i < d->syscall_data_len; i++) { 14 + struct stub_syscall *sc = &d->syscall_data[i]; 15 + 16 + switch (sc->syscall) { 17 + case STUB_SYSCALL_MMAP: 18 + res = stub_syscall6(STUB_MMAP_NR, 19 + sc->mem.addr, sc->mem.length, 20 + sc->mem.prot, 21 + MAP_SHARED | MAP_FIXED, 22 + sc->mem.fd, sc->mem.offset); 23 + if (res != sc->mem.addr) { 24 + d->err = res; 25 + d->syscall_data_len = i; 26 + return -1; 27 + } 28 + break; 29 + case STUB_SYSCALL_MUNMAP: 30 + res = stub_syscall2(__NR_munmap, 31 + sc->mem.addr, sc->mem.length); 32 + if (res) { 33 + d->err = res; 34 + d->syscall_data_len = i; 35 + return -1; 36 + } 37 + break; 38 + case STUB_SYSCALL_MPROTECT: 39 + res = stub_syscall3(__NR_mprotect, 40 + sc->mem.addr, sc->mem.length, 41 + sc->mem.prot); 42 + if (res) { 43 + d->err = res; 44 + d->syscall_data_len = i; 45 + return -1; 46 + } 47 + break; 48 + default: 49 + d->err = -95; /* EOPNOTSUPP */ 50 + d->syscall_data_len = i; 51 + return -1; 52 + } 53 + } 54 + 55 + d->err = 0; 56 + d->syscall_data_len = 0; 57 + 58 + return 0; 59 + } 60 + 61 + void __section(".__syscall_stub") 62 + stub_syscall_handler(void) 63 + { 64 + struct stub_data *d = get_stub_data(); 65 + 66 + syscall_handler(d); 67 + 68 + trap_myself(); 69 + }
+173 -14
arch/um/kernel/time.c
··· 31 31 static bool time_travel_start_set; 32 32 static unsigned long long time_travel_start; 33 33 static unsigned long long time_travel_time; 34 + static unsigned long long time_travel_shm_offset; 34 35 static LIST_HEAD(time_travel_events); 35 36 static LIST_HEAD(time_travel_irqs); 36 37 static unsigned long long time_travel_timer_interval; ··· 41 40 static unsigned int time_travel_ext_waiting; 42 41 static bool time_travel_ext_prev_request_valid; 43 42 static unsigned long long time_travel_ext_prev_request; 44 - static bool time_travel_ext_free_until_valid; 45 - static unsigned long long time_travel_ext_free_until; 43 + static unsigned long long *time_travel_ext_free_until; 44 + static unsigned long long _time_travel_ext_free_until; 45 + static u16 time_travel_shm_id; 46 + static struct um_timetravel_schedshm *time_travel_shm; 47 + static union um_timetravel_schedshm_client *time_travel_shm_client; 46 48 47 49 static void time_travel_set_time(unsigned long long ns) 48 50 { ··· 62 58 TTMH_IDLE, 63 59 TTMH_POLL, 64 60 TTMH_READ, 61 + TTMH_READ_START_ACK, 65 62 }; 63 + 64 + static u64 bc_message; 65 + int time_travel_should_print_bc_msg; 66 + 67 + void _time_travel_print_bc_msg(void) 68 + { 69 + time_travel_should_print_bc_msg = 0; 70 + printk(KERN_INFO "time-travel: received broadcast 0x%llx\n", bc_message); 71 + } 72 + 73 + static void time_travel_setup_shm(int fd, u16 id) 74 + { 75 + u32 len; 76 + 77 + time_travel_shm = os_mmap_rw_shared(fd, sizeof(*time_travel_shm)); 78 + 79 + if (!time_travel_shm) 80 + goto out; 81 + 82 + len = time_travel_shm->len; 83 + 84 + if (time_travel_shm->version != UM_TIMETRAVEL_SCHEDSHM_VERSION || 85 + len < struct_size(time_travel_shm, clients, id + 1)) { 86 + os_unmap_memory(time_travel_shm, sizeof(*time_travel_shm)); 87 + time_travel_shm = NULL; 88 + goto out; 89 + } 90 + 91 + time_travel_shm = os_mremap_rw_shared(time_travel_shm, 92 + sizeof(*time_travel_shm), 93 + len); 94 + if (!time_travel_shm) 95 + goto out; 96 + 97 + time_travel_shm_offset = time_travel_shm->current_time; 98 + time_travel_shm_client = &time_travel_shm->clients[id]; 99 + time_travel_shm_client->capa |= UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE; 100 + time_travel_shm_id = id; 101 + /* always look at that free_until from now on */ 102 + time_travel_ext_free_until = &time_travel_shm->free_until; 103 + out: 104 + os_close_file(fd); 105 + } 66 106 67 107 static void time_travel_handle_message(struct um_timetravel_msg *msg, 68 108 enum time_travel_message_handling mode) ··· 128 80 } 129 81 } 130 82 131 - ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg)); 83 + if (unlikely(mode == TTMH_READ_START_ACK)) { 84 + int fd[UM_TIMETRAVEL_SHARED_MAX_FDS]; 85 + 86 + ret = os_rcv_fd_msg(time_travel_ext_fd, fd, 87 + ARRAY_SIZE(fd), msg, sizeof(*msg)); 88 + if (ret == sizeof(*msg)) { 89 + time_travel_setup_shm(fd[UM_TIMETRAVEL_SHARED_MEMFD], 90 + msg->time & UM_TIMETRAVEL_START_ACK_ID); 91 + /* we don't use the logging for now */ 92 + os_close_file(fd[UM_TIMETRAVEL_SHARED_LOGFD]); 93 + } 94 + } else { 95 + ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg)); 96 + } 132 97 133 98 if (ret == 0) 134 99 panic("time-travel external link is broken\n"); ··· 157 96 return; 158 97 case UM_TIMETRAVEL_RUN: 159 98 time_travel_set_time(msg->time); 99 + if (time_travel_shm) { 100 + /* no request right now since we're running */ 101 + time_travel_shm_client->flags &= 102 + ~UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN; 103 + /* no ack for shared memory RUN */ 104 + return; 105 + } 160 106 break; 161 107 case UM_TIMETRAVEL_FREE_UNTIL: 162 - time_travel_ext_free_until_valid = true; 163 - time_travel_ext_free_until = msg->time; 108 + /* not supposed to get this with shm, but ignore it */ 109 + if (time_travel_shm) 110 + break; 111 + time_travel_ext_free_until = &_time_travel_ext_free_until; 112 + _time_travel_ext_free_until = msg->time; 113 + break; 114 + case UM_TIMETRAVEL_BROADCAST: 115 + bc_message = msg->time; 116 + time_travel_should_print_bc_msg = 1; 164 117 break; 165 118 } 166 119 ··· 211 136 block_signals_hard(); 212 137 os_write_file(time_travel_ext_fd, &msg, sizeof(msg)); 213 138 139 + /* no ACK expected for WAIT in shared memory mode */ 140 + if (msg.op == UM_TIMETRAVEL_WAIT && time_travel_shm) 141 + goto done; 142 + 214 143 while (msg.op != UM_TIMETRAVEL_ACK) 215 - time_travel_handle_message(&msg, TTMH_READ); 144 + time_travel_handle_message(&msg, 145 + op == UM_TIMETRAVEL_START ? 146 + TTMH_READ_START_ACK : 147 + TTMH_READ); 216 148 217 149 if (msg.seq != mseq) 218 150 panic("time-travel: ACK message has different seqno! op=%d, seq=%d != %d time=%lld\n", ··· 227 145 228 146 if (op == UM_TIMETRAVEL_GET) 229 147 time_travel_set_time(msg.time); 148 + done: 230 149 unblock_signals_hard(); 231 150 232 151 return msg.time; ··· 263 180 /* 264 181 * if we're running and are allowed to run past the request 265 182 * then we don't need to update it either 183 + * 184 + * Note for shm we ignore FREE_UNTIL messages and leave the pointer 185 + * to shared memory, and for non-shm the offset is 0. 266 186 */ 267 - if (!time_travel_ext_waiting && time_travel_ext_free_until_valid && 268 - time < time_travel_ext_free_until) 187 + if (!time_travel_ext_waiting && time_travel_ext_free_until && 188 + time < (*time_travel_ext_free_until - time_travel_shm_offset)) 269 189 return; 270 190 271 191 time_travel_ext_prev_request = time; 272 192 time_travel_ext_prev_request_valid = true; 193 + 194 + if (time_travel_shm) { 195 + union um_timetravel_schedshm_client *running; 196 + 197 + running = &time_travel_shm->clients[time_travel_shm->running_id]; 198 + 199 + if (running->capa & UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE) { 200 + time_travel_shm_client->flags |= 201 + UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN; 202 + time += time_travel_shm_offset; 203 + time_travel_shm_client->req_time = time; 204 + if (time < time_travel_shm->free_until) 205 + time_travel_shm->free_until = time; 206 + return; 207 + } 208 + } 209 + 273 210 time_travel_ext_req(UM_TIMETRAVEL_REQUEST, time); 274 211 } 275 212 276 213 void __time_travel_propagate_time(void) 277 214 { 278 215 static unsigned long long last_propagated; 216 + 217 + if (time_travel_shm) { 218 + if (time_travel_shm->running_id != time_travel_shm_id) 219 + panic("time-travel: setting time while not running\n"); 220 + time_travel_shm->current_time = time_travel_time + 221 + time_travel_shm_offset; 222 + return; 223 + } 279 224 280 225 if (last_propagated == time_travel_time) 281 226 return; ··· 320 209 * If we received an external sync point ("free until") then we 321 210 * don't have to request/wait for anything until then, unless 322 211 * we're already waiting. 212 + * 213 + * Note for shm we ignore FREE_UNTIL messages and leave the pointer 214 + * to shared memory, and for non-shm the offset is 0. 323 215 */ 324 - if (!time_travel_ext_waiting && time_travel_ext_free_until_valid && 325 - time < time_travel_ext_free_until) 216 + if (!time_travel_ext_waiting && time_travel_ext_free_until && 217 + time < (*time_travel_ext_free_until - time_travel_shm_offset)) 326 218 return false; 327 219 328 220 time_travel_ext_update_request(time); ··· 339 225 }; 340 226 341 227 time_travel_ext_prev_request_valid = false; 342 - time_travel_ext_free_until_valid = false; 228 + if (!time_travel_shm) 229 + time_travel_ext_free_until = NULL; 343 230 time_travel_ext_waiting++; 344 231 345 232 time_travel_ext_req(UM_TIMETRAVEL_WAIT, -1); ··· 363 248 364 249 static void time_travel_ext_get_time(void) 365 250 { 366 - time_travel_ext_req(UM_TIMETRAVEL_GET, -1); 251 + if (time_travel_shm) 252 + time_travel_set_time(time_travel_shm->current_time - 253 + time_travel_shm_offset); 254 + else 255 + time_travel_ext_req(UM_TIMETRAVEL_GET, -1); 367 256 } 368 257 369 258 static void __time_travel_update_time(unsigned long long ns, bool idle) ··· 994 875 return 1; 995 876 } 996 877 997 - __setup("time-travel-start", setup_time_travel_start); 878 + __setup("time-travel-start=", setup_time_travel_start); 998 879 __uml_help(setup_time_travel_start, 999 - "time-travel-start=<seconds>\n" 880 + "time-travel-start=<nanoseconds>\n" 1000 881 "Configure the UML instance's wall clock to start at this value rather than\n" 1001 882 "the host's wall clock at the time of UML boot.\n"); 883 + static struct kobject *bc_time_kobject; 884 + 885 + static ssize_t bc_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 886 + { 887 + return sprintf(buf, "0x%llx", bc_message); 888 + } 889 + 890 + static ssize_t bc_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) 891 + { 892 + int ret; 893 + u64 user_bc_message; 894 + 895 + ret = kstrtou64(buf, 0, &user_bc_message); 896 + if (ret) 897 + return ret; 898 + 899 + bc_message = user_bc_message; 900 + 901 + time_travel_ext_req(UM_TIMETRAVEL_BROADCAST, bc_message); 902 + pr_info("um: time: sent broadcast message: 0x%llx\n", bc_message); 903 + return count; 904 + } 905 + 906 + static struct kobj_attribute bc_attribute = __ATTR(bc-message, 0660, bc_show, bc_store); 907 + 908 + static int __init um_bc_start(void) 909 + { 910 + if (time_travel_mode != TT_MODE_EXTERNAL) 911 + return 0; 912 + 913 + bc_time_kobject = kobject_create_and_add("um-ext-time", kernel_kobj); 914 + if (!bc_time_kobject) 915 + return 0; 916 + 917 + if (sysfs_create_file(bc_time_kobject, &bc_attribute.attr)) 918 + pr_debug("failed to create the bc file in /sys/kernel/um_time"); 919 + 920 + return 0; 921 + } 922 + late_initcall(um_bc_start); 1002 923 #endif
+96 -459
arch/um/kernel/tlb.c
··· 15 15 #include <skas.h> 16 16 #include <kern_util.h> 17 17 18 - struct host_vm_change { 19 - struct host_vm_op { 20 - enum { NONE, MMAP, MUNMAP, MPROTECT } type; 21 - union { 22 - struct { 23 - unsigned long addr; 24 - unsigned long len; 25 - unsigned int prot; 26 - int fd; 27 - __u64 offset; 28 - } mmap; 29 - struct { 30 - unsigned long addr; 31 - unsigned long len; 32 - } munmap; 33 - struct { 34 - unsigned long addr; 35 - unsigned long len; 36 - unsigned int prot; 37 - } mprotect; 38 - } u; 39 - } ops[1]; 40 - int userspace; 41 - int index; 42 - struct mm_struct *mm; 43 - void *data; 44 - int force; 18 + struct vm_ops { 19 + struct mm_id *mm_idp; 20 + 21 + int (*mmap)(struct mm_id *mm_idp, 22 + unsigned long virt, unsigned long len, int prot, 23 + int phys_fd, unsigned long long offset); 24 + int (*unmap)(struct mm_id *mm_idp, 25 + unsigned long virt, unsigned long len); 26 + int (*mprotect)(struct mm_id *mm_idp, 27 + unsigned long virt, unsigned long len, 28 + unsigned int prot); 45 29 }; 46 30 47 - #define INIT_HVC(mm, force, userspace) \ 48 - ((struct host_vm_change) \ 49 - { .ops = { { .type = NONE } }, \ 50 - .mm = mm, \ 51 - .data = NULL, \ 52 - .userspace = userspace, \ 53 - .index = 0, \ 54 - .force = force }) 31 + static int kern_map(struct mm_id *mm_idp, 32 + unsigned long virt, unsigned long len, int prot, 33 + int phys_fd, unsigned long long offset) 34 + { 35 + /* TODO: Why is executable needed to be always set in the kernel? */ 36 + return os_map_memory((void *)virt, phys_fd, offset, len, 37 + prot & UM_PROT_READ, prot & UM_PROT_WRITE, 38 + 1); 39 + } 55 40 56 - static void report_enomem(void) 41 + static int kern_unmap(struct mm_id *mm_idp, 42 + unsigned long virt, unsigned long len) 43 + { 44 + return os_unmap_memory((void *)virt, len); 45 + } 46 + 47 + static int kern_mprotect(struct mm_id *mm_idp, 48 + unsigned long virt, unsigned long len, 49 + unsigned int prot) 50 + { 51 + return os_protect_memory((void *)virt, len, 52 + prot & UM_PROT_READ, prot & UM_PROT_WRITE, 53 + 1); 54 + } 55 + 56 + void report_enomem(void) 57 57 { 58 58 printk(KERN_ERR "UML ran out of memory on the host side! " 59 59 "This can happen due to a memory limitation or " 60 60 "vm.max_map_count has been reached.\n"); 61 61 } 62 62 63 - static int do_ops(struct host_vm_change *hvc, int end, 64 - int finished) 65 - { 66 - struct host_vm_op *op; 67 - int i, ret = 0; 68 - 69 - for (i = 0; i < end && !ret; i++) { 70 - op = &hvc->ops[i]; 71 - switch (op->type) { 72 - case MMAP: 73 - if (hvc->userspace) 74 - ret = map(&hvc->mm->context.id, op->u.mmap.addr, 75 - op->u.mmap.len, op->u.mmap.prot, 76 - op->u.mmap.fd, 77 - op->u.mmap.offset, finished, 78 - &hvc->data); 79 - else 80 - map_memory(op->u.mmap.addr, op->u.mmap.offset, 81 - op->u.mmap.len, 1, 1, 1); 82 - break; 83 - case MUNMAP: 84 - if (hvc->userspace) 85 - ret = unmap(&hvc->mm->context.id, 86 - op->u.munmap.addr, 87 - op->u.munmap.len, finished, 88 - &hvc->data); 89 - else 90 - ret = os_unmap_memory( 91 - (void *) op->u.munmap.addr, 92 - op->u.munmap.len); 93 - 94 - break; 95 - case MPROTECT: 96 - if (hvc->userspace) 97 - ret = protect(&hvc->mm->context.id, 98 - op->u.mprotect.addr, 99 - op->u.mprotect.len, 100 - op->u.mprotect.prot, 101 - finished, &hvc->data); 102 - else 103 - ret = os_protect_memory( 104 - (void *) op->u.mprotect.addr, 105 - op->u.mprotect.len, 106 - 1, 1, 1); 107 - break; 108 - default: 109 - printk(KERN_ERR "Unknown op type %d in do_ops\n", 110 - op->type); 111 - BUG(); 112 - break; 113 - } 114 - } 115 - 116 - if (ret == -ENOMEM) 117 - report_enomem(); 118 - 119 - return ret; 120 - } 121 - 122 - static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, 123 - unsigned int prot, struct host_vm_change *hvc) 124 - { 125 - __u64 offset; 126 - struct host_vm_op *last; 127 - int fd = -1, ret = 0; 128 - 129 - if (hvc->userspace) 130 - fd = phys_mapping(phys, &offset); 131 - else 132 - offset = phys; 133 - if (hvc->index != 0) { 134 - last = &hvc->ops[hvc->index - 1]; 135 - if ((last->type == MMAP) && 136 - (last->u.mmap.addr + last->u.mmap.len == virt) && 137 - (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) && 138 - (last->u.mmap.offset + last->u.mmap.len == offset)) { 139 - last->u.mmap.len += len; 140 - return 0; 141 - } 142 - } 143 - 144 - if (hvc->index == ARRAY_SIZE(hvc->ops)) { 145 - ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); 146 - hvc->index = 0; 147 - } 148 - 149 - hvc->ops[hvc->index++] = ((struct host_vm_op) 150 - { .type = MMAP, 151 - .u = { .mmap = { .addr = virt, 152 - .len = len, 153 - .prot = prot, 154 - .fd = fd, 155 - .offset = offset } 156 - } }); 157 - return ret; 158 - } 159 - 160 - static int add_munmap(unsigned long addr, unsigned long len, 161 - struct host_vm_change *hvc) 162 - { 163 - struct host_vm_op *last; 164 - int ret = 0; 165 - 166 - if (hvc->index != 0) { 167 - last = &hvc->ops[hvc->index - 1]; 168 - if ((last->type == MUNMAP) && 169 - (last->u.munmap.addr + last->u.mmap.len == addr)) { 170 - last->u.munmap.len += len; 171 - return 0; 172 - } 173 - } 174 - 175 - if (hvc->index == ARRAY_SIZE(hvc->ops)) { 176 - ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); 177 - hvc->index = 0; 178 - } 179 - 180 - hvc->ops[hvc->index++] = ((struct host_vm_op) 181 - { .type = MUNMAP, 182 - .u = { .munmap = { .addr = addr, 183 - .len = len } } }); 184 - return ret; 185 - } 186 - 187 - static int add_mprotect(unsigned long addr, unsigned long len, 188 - unsigned int prot, struct host_vm_change *hvc) 189 - { 190 - struct host_vm_op *last; 191 - int ret = 0; 192 - 193 - if (hvc->index != 0) { 194 - last = &hvc->ops[hvc->index - 1]; 195 - if ((last->type == MPROTECT) && 196 - (last->u.mprotect.addr + last->u.mprotect.len == addr) && 197 - (last->u.mprotect.prot == prot)) { 198 - last->u.mprotect.len += len; 199 - return 0; 200 - } 201 - } 202 - 203 - if (hvc->index == ARRAY_SIZE(hvc->ops)) { 204 - ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); 205 - hvc->index = 0; 206 - } 207 - 208 - hvc->ops[hvc->index++] = ((struct host_vm_op) 209 - { .type = MPROTECT, 210 - .u = { .mprotect = { .addr = addr, 211 - .len = len, 212 - .prot = prot } } }); 213 - return ret; 214 - } 215 - 216 - #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) 217 - 218 63 static inline int update_pte_range(pmd_t *pmd, unsigned long addr, 219 64 unsigned long end, 220 - struct host_vm_change *hvc) 65 + struct vm_ops *ops) 221 66 { 222 67 pte_t *pte; 223 68 int r, w, x, prot, ret = 0; ··· 80 235 81 236 prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | 82 237 (x ? UM_PROT_EXEC : 0)); 83 - if (hvc->force || pte_newpage(*pte)) { 238 + if (pte_newpage(*pte)) { 84 239 if (pte_present(*pte)) { 85 - if (pte_newpage(*pte)) 86 - ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, 87 - PAGE_SIZE, prot, hvc); 240 + if (pte_newpage(*pte)) { 241 + __u64 offset; 242 + unsigned long phys = 243 + pte_val(*pte) & PAGE_MASK; 244 + int fd = phys_mapping(phys, &offset); 245 + 246 + ret = ops->mmap(ops->mm_idp, addr, 247 + PAGE_SIZE, prot, fd, 248 + offset); 249 + } 88 250 } else 89 - ret = add_munmap(addr, PAGE_SIZE, hvc); 251 + ret = ops->unmap(ops->mm_idp, addr, PAGE_SIZE); 90 252 } else if (pte_newprot(*pte)) 91 - ret = add_mprotect(addr, PAGE_SIZE, prot, hvc); 253 + ret = ops->mprotect(ops->mm_idp, addr, PAGE_SIZE, prot); 92 254 *pte = pte_mkuptodate(*pte); 93 255 } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret)); 94 256 return ret; ··· 103 251 104 252 static inline int update_pmd_range(pud_t *pud, unsigned long addr, 105 253 unsigned long end, 106 - struct host_vm_change *hvc) 254 + struct vm_ops *ops) 107 255 { 108 256 pmd_t *pmd; 109 257 unsigned long next; ··· 113 261 do { 114 262 next = pmd_addr_end(addr, end); 115 263 if (!pmd_present(*pmd)) { 116 - if (hvc->force || pmd_newpage(*pmd)) { 117 - ret = add_munmap(addr, next - addr, hvc); 264 + if (pmd_newpage(*pmd)) { 265 + ret = ops->unmap(ops->mm_idp, addr, 266 + next - addr); 118 267 pmd_mkuptodate(*pmd); 119 268 } 120 269 } 121 - else ret = update_pte_range(pmd, addr, next, hvc); 270 + else ret = update_pte_range(pmd, addr, next, ops); 122 271 } while (pmd++, addr = next, ((addr < end) && !ret)); 123 272 return ret; 124 273 } 125 274 126 275 static inline int update_pud_range(p4d_t *p4d, unsigned long addr, 127 276 unsigned long end, 128 - struct host_vm_change *hvc) 277 + struct vm_ops *ops) 129 278 { 130 279 pud_t *pud; 131 280 unsigned long next; ··· 136 283 do { 137 284 next = pud_addr_end(addr, end); 138 285 if (!pud_present(*pud)) { 139 - if (hvc->force || pud_newpage(*pud)) { 140 - ret = add_munmap(addr, next - addr, hvc); 286 + if (pud_newpage(*pud)) { 287 + ret = ops->unmap(ops->mm_idp, addr, 288 + next - addr); 141 289 pud_mkuptodate(*pud); 142 290 } 143 291 } 144 - else ret = update_pmd_range(pud, addr, next, hvc); 292 + else ret = update_pmd_range(pud, addr, next, ops); 145 293 } while (pud++, addr = next, ((addr < end) && !ret)); 146 294 return ret; 147 295 } 148 296 149 297 static inline int update_p4d_range(pgd_t *pgd, unsigned long addr, 150 298 unsigned long end, 151 - struct host_vm_change *hvc) 299 + struct vm_ops *ops) 152 300 { 153 301 p4d_t *p4d; 154 302 unsigned long next; ··· 159 305 do { 160 306 next = p4d_addr_end(addr, end); 161 307 if (!p4d_present(*p4d)) { 162 - if (hvc->force || p4d_newpage(*p4d)) { 163 - ret = add_munmap(addr, next - addr, hvc); 308 + if (p4d_newpage(*p4d)) { 309 + ret = ops->unmap(ops->mm_idp, addr, 310 + next - addr); 164 311 p4d_mkuptodate(*p4d); 165 312 } 166 313 } else 167 - ret = update_pud_range(p4d, addr, next, hvc); 314 + ret = update_pud_range(p4d, addr, next, ops); 168 315 } while (p4d++, addr = next, ((addr < end) && !ret)); 169 316 return ret; 170 317 } 171 318 172 - static void fix_range_common(struct mm_struct *mm, unsigned long start_addr, 173 - unsigned long end_addr, int force) 319 + int um_tlb_sync(struct mm_struct *mm) 174 320 { 175 321 pgd_t *pgd; 176 - struct host_vm_change hvc; 177 - unsigned long addr = start_addr, next; 178 - int ret = 0, userspace = 1; 322 + struct vm_ops ops; 323 + unsigned long addr = mm->context.sync_tlb_range_from, next; 324 + int ret = 0; 179 325 180 - hvc = INIT_HVC(mm, force, userspace); 326 + if (mm->context.sync_tlb_range_to == 0) 327 + return 0; 328 + 329 + ops.mm_idp = &mm->context.id; 330 + if (mm == &init_mm) { 331 + ops.mmap = kern_map; 332 + ops.unmap = kern_unmap; 333 + ops.mprotect = kern_mprotect; 334 + } else { 335 + ops.mmap = map; 336 + ops.unmap = unmap; 337 + ops.mprotect = protect; 338 + } 339 + 181 340 pgd = pgd_offset(mm, addr); 182 341 do { 183 - next = pgd_addr_end(addr, end_addr); 342 + next = pgd_addr_end(addr, mm->context.sync_tlb_range_to); 184 343 if (!pgd_present(*pgd)) { 185 - if (force || pgd_newpage(*pgd)) { 186 - ret = add_munmap(addr, next - addr, &hvc); 344 + if (pgd_newpage(*pgd)) { 345 + ret = ops.unmap(ops.mm_idp, addr, 346 + next - addr); 187 347 pgd_mkuptodate(*pgd); 188 348 } 189 349 } else 190 - ret = update_p4d_range(pgd, addr, next, &hvc); 191 - } while (pgd++, addr = next, ((addr < end_addr) && !ret)); 350 + ret = update_p4d_range(pgd, addr, next, &ops); 351 + } while (pgd++, addr = next, 352 + ((addr < mm->context.sync_tlb_range_to) && !ret)); 192 353 193 - if (!ret) 194 - ret = do_ops(&hvc, hvc.index, 1); 354 + if (ret == -ENOMEM) 355 + report_enomem(); 195 356 196 - /* This is not an else because ret is modified above */ 197 - if (ret) { 198 - struct mm_id *mm_idp = &current->mm->context.id; 357 + mm->context.sync_tlb_range_from = 0; 358 + mm->context.sync_tlb_range_to = 0; 199 359 200 - printk(KERN_ERR "fix_range_common: failed, killing current " 201 - "process: %d\n", task_tgid_vnr(current)); 202 - mm_idp->kill = 1; 203 - } 204 - } 205 - 206 - static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) 207 - { 208 - struct mm_struct *mm; 209 - pgd_t *pgd; 210 - p4d_t *p4d; 211 - pud_t *pud; 212 - pmd_t *pmd; 213 - pte_t *pte; 214 - unsigned long addr, last; 215 - int updated = 0, err = 0, force = 0, userspace = 0; 216 - struct host_vm_change hvc; 217 - 218 - mm = &init_mm; 219 - hvc = INIT_HVC(mm, force, userspace); 220 - for (addr = start; addr < end;) { 221 - pgd = pgd_offset(mm, addr); 222 - if (!pgd_present(*pgd)) { 223 - last = ADD_ROUND(addr, PGDIR_SIZE); 224 - if (last > end) 225 - last = end; 226 - if (pgd_newpage(*pgd)) { 227 - updated = 1; 228 - err = add_munmap(addr, last - addr, &hvc); 229 - if (err < 0) 230 - panic("munmap failed, errno = %d\n", 231 - -err); 232 - } 233 - addr = last; 234 - continue; 235 - } 236 - 237 - p4d = p4d_offset(pgd, addr); 238 - if (!p4d_present(*p4d)) { 239 - last = ADD_ROUND(addr, P4D_SIZE); 240 - if (last > end) 241 - last = end; 242 - if (p4d_newpage(*p4d)) { 243 - updated = 1; 244 - err = add_munmap(addr, last - addr, &hvc); 245 - if (err < 0) 246 - panic("munmap failed, errno = %d\n", 247 - -err); 248 - } 249 - addr = last; 250 - continue; 251 - } 252 - 253 - pud = pud_offset(p4d, addr); 254 - if (!pud_present(*pud)) { 255 - last = ADD_ROUND(addr, PUD_SIZE); 256 - if (last > end) 257 - last = end; 258 - if (pud_newpage(*pud)) { 259 - updated = 1; 260 - err = add_munmap(addr, last - addr, &hvc); 261 - if (err < 0) 262 - panic("munmap failed, errno = %d\n", 263 - -err); 264 - } 265 - addr = last; 266 - continue; 267 - } 268 - 269 - pmd = pmd_offset(pud, addr); 270 - if (!pmd_present(*pmd)) { 271 - last = ADD_ROUND(addr, PMD_SIZE); 272 - if (last > end) 273 - last = end; 274 - if (pmd_newpage(*pmd)) { 275 - updated = 1; 276 - err = add_munmap(addr, last - addr, &hvc); 277 - if (err < 0) 278 - panic("munmap failed, errno = %d\n", 279 - -err); 280 - } 281 - addr = last; 282 - continue; 283 - } 284 - 285 - pte = pte_offset_kernel(pmd, addr); 286 - if (!pte_present(*pte) || pte_newpage(*pte)) { 287 - updated = 1; 288 - err = add_munmap(addr, PAGE_SIZE, &hvc); 289 - if (err < 0) 290 - panic("munmap failed, errno = %d\n", 291 - -err); 292 - if (pte_present(*pte)) 293 - err = add_mmap(addr, pte_val(*pte) & PAGE_MASK, 294 - PAGE_SIZE, 0, &hvc); 295 - } 296 - else if (pte_newprot(*pte)) { 297 - updated = 1; 298 - err = add_mprotect(addr, PAGE_SIZE, 0, &hvc); 299 - } 300 - addr += PAGE_SIZE; 301 - } 302 - if (!err) 303 - err = do_ops(&hvc, hvc.index, 1); 304 - 305 - if (err < 0) 306 - panic("flush_tlb_kernel failed, errno = %d\n", err); 307 - return updated; 308 - } 309 - 310 - void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) 311 - { 312 - pgd_t *pgd; 313 - p4d_t *p4d; 314 - pud_t *pud; 315 - pmd_t *pmd; 316 - pte_t *pte; 317 - struct mm_struct *mm = vma->vm_mm; 318 - void *flush = NULL; 319 - int r, w, x, prot, err = 0; 320 - struct mm_id *mm_id; 321 - 322 - address &= PAGE_MASK; 323 - 324 - pgd = pgd_offset(mm, address); 325 - if (!pgd_present(*pgd)) 326 - goto kill; 327 - 328 - p4d = p4d_offset(pgd, address); 329 - if (!p4d_present(*p4d)) 330 - goto kill; 331 - 332 - pud = pud_offset(p4d, address); 333 - if (!pud_present(*pud)) 334 - goto kill; 335 - 336 - pmd = pmd_offset(pud, address); 337 - if (!pmd_present(*pmd)) 338 - goto kill; 339 - 340 - pte = pte_offset_kernel(pmd, address); 341 - 342 - r = pte_read(*pte); 343 - w = pte_write(*pte); 344 - x = pte_exec(*pte); 345 - if (!pte_young(*pte)) { 346 - r = 0; 347 - w = 0; 348 - } else if (!pte_dirty(*pte)) { 349 - w = 0; 350 - } 351 - 352 - mm_id = &mm->context.id; 353 - prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | 354 - (x ? UM_PROT_EXEC : 0)); 355 - if (pte_newpage(*pte)) { 356 - if (pte_present(*pte)) { 357 - unsigned long long offset; 358 - int fd; 359 - 360 - fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); 361 - err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, 362 - 1, &flush); 363 - } 364 - else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); 365 - } 366 - else if (pte_newprot(*pte)) 367 - err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush); 368 - 369 - if (err) { 370 - if (err == -ENOMEM) 371 - report_enomem(); 372 - 373 - goto kill; 374 - } 375 - 376 - *pte = pte_mkuptodate(*pte); 377 - 378 - return; 379 - 380 - kill: 381 - printk(KERN_ERR "Failed to flush page for address 0x%lx\n", address); 382 - force_sig(SIGKILL); 360 + return ret; 383 361 } 384 362 385 363 void flush_tlb_all(void) ··· 226 540 flush_tlb_mm(current->mm); 227 541 } 228 542 229 - void flush_tlb_kernel_range(unsigned long start, unsigned long end) 230 - { 231 - flush_tlb_kernel_range_common(start, end); 232 - } 233 - 234 - void flush_tlb_kernel_vm(void) 235 - { 236 - flush_tlb_kernel_range_common(start_vm, end_vm); 237 - } 238 - 239 - void __flush_tlb_one(unsigned long addr) 240 - { 241 - flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE); 242 - } 243 - 244 - static void fix_range(struct mm_struct *mm, unsigned long start_addr, 245 - unsigned long end_addr, int force) 246 - { 247 - /* 248 - * Don't bother flushing if this address space is about to be 249 - * destroyed. 250 - */ 251 - if (atomic_read(&mm->mm_users) == 0) 252 - return; 253 - 254 - fix_range_common(mm, start_addr, end_addr, force); 255 - } 256 - 257 - void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 258 - unsigned long end) 259 - { 260 - if (vma->vm_mm == NULL) 261 - flush_tlb_kernel_range_common(start, end); 262 - else fix_range(vma->vm_mm, start, end, 0); 263 - } 264 - EXPORT_SYMBOL(flush_tlb_range); 265 - 266 543 void flush_tlb_mm(struct mm_struct *mm) 267 544 { 268 545 struct vm_area_struct *vma; 269 546 VMA_ITERATOR(vmi, mm, 0); 270 547 271 548 for_each_vma(vmi, vma) 272 - fix_range(mm, vma->vm_start, vma->vm_end, 0); 273 - } 274 - 275 - void force_flush_all(void) 276 - { 277 - struct mm_struct *mm = current->mm; 278 - struct vm_area_struct *vma; 279 - VMA_ITERATOR(vmi, mm, 0); 280 - 281 - mmap_read_lock(mm); 282 - for_each_vma(vmi, vma) 283 - fix_range(mm, vma->vm_start, vma->vm_end, 1); 284 - mmap_read_unlock(mm); 549 + um_tlb_mark_sync(mm, vma->vm_start, vma->vm_end); 285 550 }
+12 -3
arch/um/kernel/trap.c
··· 113 113 #if 0 114 114 WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte))); 115 115 #endif 116 - flush_tlb_page(vma, address); 116 + 117 117 out: 118 118 mmap_read_unlock(mm); 119 119 out_nosemaphore: ··· 210 210 if (!is_user && regs) 211 211 current->thread.segv_regs = container_of(regs, struct pt_regs, regs); 212 212 213 - if (!is_user && (address >= start_vm) && (address < end_vm)) { 214 - flush_tlb_kernel_vm(); 213 + if (!is_user && init_mm.context.sync_tlb_range_to) { 214 + /* 215 + * Kernel has pending updates from set_ptes that were not 216 + * flushed yet. Syncing them should fix the pagefault (if not 217 + * we'll get here again and panic). 218 + */ 219 + err = um_tlb_sync(&init_mm); 220 + if (err == -ENOMEM) 221 + report_enomem(); 222 + if (err) 223 + panic("Failed to sync kernel TLBs: %d", err); 215 224 goto out; 216 225 } 217 226 else if (current->mm == NULL) {
-3
arch/um/kernel/um_arch.c
··· 126 126 unsigned long start_vm; 127 127 unsigned long end_vm; 128 128 129 - /* Set in uml_ncpus_setup */ 130 - int ncpus = 1; 131 - 132 129 /* Set in early boot */ 133 130 static int have_root __initdata; 134 131 static int have_console __initdata;
+65 -29
arch/um/os-Linux/file.c
··· 17 17 #include <sys/stat.h> 18 18 #include <sys/sysmacros.h> 19 19 #include <sys/un.h> 20 + #include <sys/mman.h> 20 21 #include <sys/types.h> 21 22 #include <sys/eventfd.h> 22 23 #include <poll.h> ··· 239 238 close(fd); 240 239 out: 241 240 return err; 241 + } 242 + 243 + int os_dup_file(int fd) 244 + { 245 + int new_fd = dup(fd); 246 + 247 + if (new_fd < 0) 248 + return -errno; 249 + 250 + return new_fd; 242 251 } 243 252 244 253 void os_close_file(int fd) ··· 513 502 return 0; 514 503 } 515 504 516 - int os_rcv_fd(int fd, int *helper_pid_out) 505 + /** 506 + * os_rcv_fd_msg - receive message with (optional) FDs 507 + * @fd: the FD to receive from 508 + * @fds: the array for FDs to write to 509 + * @n_fds: number of FDs to receive (@fds array size) 510 + * @data: the message buffer 511 + * @data_len: the size of the message to receive 512 + * 513 + * Receive a message with FDs. 514 + * 515 + * Returns: the size of the received message, or an error code 516 + */ 517 + ssize_t os_rcv_fd_msg(int fd, int *fds, unsigned int n_fds, 518 + void *data, size_t data_len) 517 519 { 518 - int new, n; 519 - char buf[CMSG_SPACE(sizeof(new))]; 520 - struct msghdr msg; 520 + char buf[CMSG_SPACE(sizeof(*fds) * n_fds)]; 521 521 struct cmsghdr *cmsg; 522 - struct iovec iov; 523 - 524 - msg.msg_name = NULL; 525 - msg.msg_namelen = 0; 526 - iov = ((struct iovec) { .iov_base = helper_pid_out, 527 - .iov_len = sizeof(*helper_pid_out) }); 528 - msg.msg_iov = &iov; 529 - msg.msg_iovlen = 1; 530 - msg.msg_control = buf; 531 - msg.msg_controllen = sizeof(buf); 532 - msg.msg_flags = 0; 522 + struct iovec iov = { 523 + .iov_base = data, 524 + .iov_len = data_len, 525 + }; 526 + struct msghdr msg = { 527 + .msg_iov = &iov, 528 + .msg_iovlen = 1, 529 + .msg_control = buf, 530 + .msg_controllen = sizeof(buf), 531 + }; 532 + int n; 533 533 534 534 n = recvmsg(fd, &msg, 0); 535 535 if (n < 0) 536 536 return -errno; 537 - else if (n != iov.iov_len) 538 - *helper_pid_out = -1; 539 537 540 538 cmsg = CMSG_FIRSTHDR(&msg); 541 - if (cmsg == NULL) { 542 - printk(UM_KERN_ERR "rcv_fd didn't receive anything, " 543 - "error = %d\n", errno); 544 - return -1; 545 - } 546 - if ((cmsg->cmsg_level != SOL_SOCKET) || 547 - (cmsg->cmsg_type != SCM_RIGHTS)) { 548 - printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n"); 549 - return -1; 550 - } 539 + if (!cmsg || 540 + cmsg->cmsg_level != SOL_SOCKET || 541 + cmsg->cmsg_type != SCM_RIGHTS) 542 + return n; 551 543 552 - new = ((int *) CMSG_DATA(cmsg))[0]; 553 - return new; 544 + memcpy(fds, CMSG_DATA(cmsg), cmsg->cmsg_len); 545 + return n; 554 546 } 555 547 556 548 int os_create_unix_socket(const char *file, int len, int close_on_exec) ··· 718 704 } 719 705 720 706 return -EIO; 707 + } 708 + 709 + void *os_mmap_rw_shared(int fd, size_t size) 710 + { 711 + void *res = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 712 + 713 + if (res == MAP_FAILED) 714 + return NULL; 715 + 716 + return res; 717 + } 718 + 719 + void *os_mremap_rw_shared(void *old_addr, size_t old_size, size_t new_size) 720 + { 721 + void *res; 722 + 723 + res = mremap(old_addr, old_size, new_size, MREMAP_MAYMOVE, NULL); 724 + 725 + if (res == MAP_FAILED) 726 + return NULL; 727 + 728 + return res; 721 729 }
+98 -20
arch/um/os-Linux/signal.c
··· 8 8 9 9 #include <stdlib.h> 10 10 #include <stdarg.h> 11 + #include <stdbool.h> 11 12 #include <errno.h> 12 13 #include <signal.h> 13 14 #include <string.h> ··· 66 65 67 66 int signals_enabled; 68 67 #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT 69 - static int signals_blocked; 70 - #else 71 - #define signals_blocked 0 68 + static int signals_blocked, signals_blocked_pending; 72 69 #endif 73 70 static unsigned int signals_pending; 74 71 static unsigned int signals_active = 0; ··· 75 76 { 76 77 int enabled = signals_enabled; 77 78 78 - if ((signals_blocked || !enabled) && (sig == SIGIO)) { 79 + #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT 80 + if ((signals_blocked || 81 + __atomic_load_n(&signals_blocked_pending, __ATOMIC_SEQ_CST)) && 82 + (sig == SIGIO)) { 83 + /* increment so unblock will do another round */ 84 + __atomic_add_fetch(&signals_blocked_pending, 1, 85 + __ATOMIC_SEQ_CST); 86 + return; 87 + } 88 + #endif 89 + 90 + if (!enabled && (sig == SIGIO)) { 79 91 /* 80 92 * 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.) 93 + * handlers. This will mark signals_pending by itself 94 + * (only if necessary.) 95 + * Note we won't get here if signals are hard-blocked 96 + * (which is handled above), in that case the hard- 97 + * unblock will handle things. 84 98 */ 85 - if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL) 99 + if (time_travel_mode == TT_MODE_EXTERNAL) 86 100 sigio_run_timetravel_handlers(); 87 101 else 88 102 signals_pending |= SIGIO_MASK; ··· 392 380 #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT 393 381 void mark_sigio_pending(void) 394 382 { 383 + /* 384 + * It would seem that this should be atomic so 385 + * it isn't a read-modify-write with a signal 386 + * that could happen in the middle, losing the 387 + * value set by the signal. 388 + * 389 + * However, this function is only called when in 390 + * time-travel=ext simulation mode, in which case 391 + * the only signal ever pending is SIGIO, which 392 + * is blocked while this can be called, and the 393 + * timer signal (SIGALRM) cannot happen. 394 + */ 395 395 signals_pending |= SIGIO_MASK; 396 396 } 397 397 398 398 void block_signals_hard(void) 399 399 { 400 - if (signals_blocked) 401 - return; 402 - signals_blocked = 1; 400 + signals_blocked++; 403 401 barrier(); 404 402 } 405 403 406 404 void unblock_signals_hard(void) 407 405 { 406 + static bool unblocking; 407 + 408 408 if (!signals_blocked) 409 + panic("unblocking signals while not blocked"); 410 + 411 + if (--signals_blocked) 409 412 return; 410 - /* Must be set to 0 before we check the pending bits etc. */ 411 - signals_blocked = 0; 413 + /* 414 + * Must be set to 0 before we check pending so the 415 + * SIGIO handler will run as normal unless we're still 416 + * going to process signals_blocked_pending. 417 + */ 412 418 barrier(); 413 419 414 - if (signals_pending && signals_enabled) { 415 - /* this is a bit inefficient, but that's not really important */ 416 - block_signals(); 417 - unblock_signals(); 418 - } else if (signals_pending & SIGIO_MASK) { 419 - /* we need to run time-travel handlers even if not enabled */ 420 - sigio_run_timetravel_handlers(); 420 + /* 421 + * Note that block_signals_hard()/unblock_signals_hard() can be called 422 + * within the unblock_signals()/sigio_run_timetravel_handlers() below. 423 + * This would still be prone to race conditions since it's actually a 424 + * call _within_ e.g. vu_req_read_message(), where we observed this 425 + * issue, which loops. Thus, if the inner call handles the recorded 426 + * pending signals, we can get out of the inner call with the real 427 + * signal hander no longer blocked, and still have a race. Thus don't 428 + * handle unblocking in the inner call, if it happens, but only in 429 + * the outermost call - 'unblocking' serves as an ownership for the 430 + * signals_blocked_pending decrement. 431 + */ 432 + if (unblocking) 433 + return; 434 + unblocking = true; 435 + 436 + while (__atomic_load_n(&signals_blocked_pending, __ATOMIC_SEQ_CST)) { 437 + if (signals_enabled) { 438 + /* signals are enabled so we can touch this */ 439 + signals_pending |= SIGIO_MASK; 440 + /* 441 + * this is a bit inefficient, but that's 442 + * not really important 443 + */ 444 + block_signals(); 445 + unblock_signals(); 446 + } else { 447 + /* 448 + * we need to run time-travel handlers even 449 + * if not enabled 450 + */ 451 + sigio_run_timetravel_handlers(); 452 + } 453 + 454 + /* 455 + * The decrement of signals_blocked_pending must be atomic so 456 + * that the signal handler will either happen before or after 457 + * the decrement, not during a read-modify-write: 458 + * - If it happens before, it can increment it and we'll 459 + * decrement it and do another round in the loop. 460 + * - If it happens after it'll see 0 for both signals_blocked 461 + * and signals_blocked_pending and thus run the handler as 462 + * usual (subject to signals_enabled, but that's unrelated.) 463 + * 464 + * Note that a call to unblock_signals_hard() within the calls 465 + * to unblock_signals() or sigio_run_timetravel_handlers() above 466 + * will do nothing due to the 'unblocking' state, so this cannot 467 + * underflow as the only one decrementing will be the outermost 468 + * one. 469 + */ 470 + if (__atomic_sub_fetch(&signals_blocked_pending, 1, 471 + __ATOMIC_SEQ_CST) < 0) 472 + panic("signals_blocked_pending underflow"); 421 473 } 474 + 475 + unblocking = false; 422 476 } 423 477 #endif 424 478
+148 -113
arch/um/os-Linux/skas/mem.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 + * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net> 3 4 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 5 */ 5 6 ··· 20 19 #include <sysdep/stub.h> 21 20 #include "../internal.h" 22 21 23 - extern char batch_syscall_stub[], __syscall_stub_start[]; 22 + extern char __syscall_stub_start[]; 23 + 24 + void syscall_stub_dump_error(struct mm_id *mm_idp) 25 + { 26 + struct stub_data *proc_data = (void *)mm_idp->stack; 27 + struct stub_syscall *sc; 28 + 29 + if (proc_data->syscall_data_len < 0 || 30 + proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data)) 31 + panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!", 32 + proc_data->syscall_data_len, 33 + mm_idp->syscall_data_len); 34 + 35 + sc = &proc_data->syscall_data[proc_data->syscall_data_len]; 36 + 37 + printk(UM_KERN_ERR "%s : length = %d, last offset = %d", 38 + __func__, mm_idp->syscall_data_len, 39 + proc_data->syscall_data_len); 40 + printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n", 41 + __func__, sc->syscall, proc_data->err); 42 + 43 + print_hex_dump(UM_KERN_ERR, " syscall data: ", 0, 44 + 16, 4, sc, sizeof(*sc), 0); 45 + } 24 46 25 47 static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 26 48 unsigned long *stack) ··· 60 36 static int __init init_syscall_regs(void) 61 37 { 62 38 get_safe_registers(syscall_regs, NULL); 39 + 63 40 syscall_regs[REGS_IP_INDEX] = STUB_CODE + 64 - ((unsigned long) batch_syscall_stub - 41 + ((unsigned long) stub_syscall_handler - 65 42 (unsigned long) __syscall_stub_start); 66 - syscall_regs[REGS_SP_INDEX] = STUB_DATA; 43 + syscall_regs[REGS_SP_INDEX] = STUB_DATA + 44 + offsetof(struct stub_data, sigstack) + 45 + sizeof(((struct stub_data *) 0)->sigstack) - 46 + sizeof(void *); 67 47 68 48 return 0; 69 49 } 70 50 71 51 __initcall(init_syscall_regs); 72 52 73 - static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 53 + static inline long do_syscall_stub(struct mm_id *mm_idp) 74 54 { 55 + struct stub_data *proc_data = (void *)mm_idp->stack; 75 56 int n, i; 76 - long ret, offset; 77 - unsigned long * data; 78 - unsigned long * syscall; 79 57 int err, pid = mm_idp->u.pid; 80 58 81 59 n = ptrace_setregs(pid, syscall_regs); ··· 89 63 __func__, -n); 90 64 } 91 65 66 + /* Inform process how much we have filled in. */ 67 + proc_data->syscall_data_len = mm_idp->syscall_data_len; 68 + 92 69 err = ptrace(PTRACE_CONT, pid, 0, 0); 93 70 if (err) 94 71 panic("Failed to continue stub, pid = %d, errno = %d\n", pid, ··· 100 71 wait_stub_done(pid); 101 72 102 73 /* 103 - * When the stub stops, we find the following values on the 104 - * beginning of the stack: 105 - * (long )return_value 106 - * (long )offset to failed sycall-data (0, if no error) 74 + * proc_data->err will be non-zero if there was an (unexpected) error. 75 + * In that case, syscall_data_len points to the last executed syscall, 76 + * otherwise it will be zero (but we do not need to rely on that). 107 77 */ 108 - ret = *((unsigned long *) mm_idp->stack); 109 - offset = *((unsigned long *) mm_idp->stack + 1); 110 - if (offset) { 111 - data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); 112 - printk(UM_KERN_ERR "%s : ret = %ld, offset = %ld, data = %p\n", 113 - __func__, ret, offset, data); 114 - syscall = (unsigned long *)((unsigned long)data + data[0]); 115 - printk(UM_KERN_ERR "%s: syscall %ld failed, return value = 0x%lx, expected return value = 0x%lx\n", 116 - __func__, syscall[0], ret, syscall[7]); 117 - printk(UM_KERN_ERR " syscall parameters: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 118 - syscall[1], syscall[2], syscall[3], 119 - syscall[4], syscall[5], syscall[6]); 120 - for (n = 1; n < data[0]/sizeof(long); n++) { 121 - if (n == 1) 122 - printk(UM_KERN_ERR " additional syscall data:"); 123 - if (n % 4 == 1) 124 - printk("\n" UM_KERN_ERR " "); 125 - printk(" 0x%lx", data[n]); 126 - } 127 - if (n > 1) 128 - printk("\n"); 78 + if (proc_data->err < 0) { 79 + syscall_stub_dump_error(mm_idp); 80 + 81 + /* Store error code in case someone tries to add more syscalls */ 82 + mm_idp->syscall_data_len = proc_data->err; 83 + } else { 84 + mm_idp->syscall_data_len = 0; 129 85 } 130 - else ret = 0; 131 86 132 - *addr = check_init_stack(mm_idp, NULL); 133 - 134 - return ret; 87 + return mm_idp->syscall_data_len; 135 88 } 136 89 137 - long run_syscall_stub(struct mm_id * mm_idp, int syscall, 138 - unsigned long *args, long expected, void **addr, 139 - int done) 90 + int syscall_stub_flush(struct mm_id *mm_idp) 140 91 { 141 - unsigned long *stack = check_init_stack(mm_idp, *addr); 92 + int res; 142 93 143 - *stack += sizeof(long); 144 - stack += *stack / sizeof(long); 94 + if (mm_idp->syscall_data_len == 0) 95 + return 0; 145 96 146 - *stack++ = syscall; 147 - *stack++ = args[0]; 148 - *stack++ = args[1]; 149 - *stack++ = args[2]; 150 - *stack++ = args[3]; 151 - *stack++ = args[4]; 152 - *stack++ = args[5]; 153 - *stack++ = expected; 154 - *stack = 0; 97 + /* If an error happened already, report it and reset the state. */ 98 + if (mm_idp->syscall_data_len < 0) { 99 + res = mm_idp->syscall_data_len; 100 + mm_idp->syscall_data_len = 0; 101 + return res; 102 + } 155 103 156 - if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < 157 - UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { 158 - *addr = stack; 104 + res = do_syscall_stub(mm_idp); 105 + mm_idp->syscall_data_len = 0; 106 + 107 + return res; 108 + } 109 + 110 + struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp) 111 + { 112 + struct stub_syscall *sc; 113 + struct stub_data *proc_data = (struct stub_data *) mm_idp->stack; 114 + 115 + if (mm_idp->syscall_data_len > 0 && 116 + mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data)) 117 + do_syscall_stub(mm_idp); 118 + 119 + if (mm_idp->syscall_data_len < 0) { 120 + /* Return dummy to retain error state. */ 121 + sc = &proc_data->syscall_data[0]; 122 + } else { 123 + sc = &proc_data->syscall_data[mm_idp->syscall_data_len]; 124 + mm_idp->syscall_data_len += 1; 125 + } 126 + memset(sc, 0, sizeof(*sc)); 127 + 128 + return sc; 129 + } 130 + 131 + static struct stub_syscall *syscall_stub_get_previous(struct mm_id *mm_idp, 132 + int syscall_type, 133 + unsigned long virt) 134 + { 135 + if (mm_idp->syscall_data_len > 0) { 136 + struct stub_data *proc_data = (void *) mm_idp->stack; 137 + struct stub_syscall *sc; 138 + 139 + sc = &proc_data->syscall_data[mm_idp->syscall_data_len - 1]; 140 + 141 + if (sc->syscall == syscall_type && 142 + sc->mem.addr + sc->mem.length == virt) 143 + return sc; 144 + } 145 + 146 + return NULL; 147 + } 148 + 149 + int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot, 150 + int phys_fd, unsigned long long offset) 151 + { 152 + struct stub_syscall *sc; 153 + 154 + /* Compress with previous syscall if that is possible */ 155 + sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MMAP, virt); 156 + if (sc && sc->mem.prot == prot && sc->mem.fd == phys_fd && 157 + sc->mem.offset == MMAP_OFFSET(offset - sc->mem.length)) { 158 + sc->mem.length += len; 159 159 return 0; 160 160 } 161 161 162 - return do_syscall_stub(mm_idp, addr); 163 - } 164 - 165 - long syscall_stub_data(struct mm_id * mm_idp, 166 - unsigned long *data, int data_count, 167 - void **addr, void **stub_addr) 168 - { 169 - unsigned long *stack; 170 - int ret = 0; 171 - 172 - /* 173 - * If *addr still is uninitialized, it *must* contain NULL. 174 - * Thus in this case do_syscall_stub correctly won't be called. 175 - */ 176 - if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= 177 - UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { 178 - ret = do_syscall_stub(mm_idp, addr); 179 - /* in case of error, don't overwrite data on stack */ 180 - if (ret) 181 - return ret; 182 - } 183 - 184 - stack = check_init_stack(mm_idp, *addr); 185 - *addr = stack; 186 - 187 - *stack = data_count * sizeof(long); 188 - 189 - memcpy(stack + 1, data, data_count * sizeof(long)); 190 - 191 - *stub_addr = (void *)(((unsigned long)(stack + 1) & 192 - ~UM_KERN_PAGE_MASK) + STUB_DATA); 162 + sc = syscall_stub_alloc(mm_idp); 163 + sc->syscall = STUB_SYSCALL_MMAP; 164 + sc->mem.addr = virt; 165 + sc->mem.length = len; 166 + sc->mem.prot = prot; 167 + sc->mem.fd = phys_fd; 168 + sc->mem.offset = MMAP_OFFSET(offset); 193 169 194 170 return 0; 195 171 } 196 172 197 - int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, 198 - int phys_fd, unsigned long long offset, int done, void **data) 173 + int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len) 199 174 { 200 - int ret; 201 - unsigned long args[] = { virt, len, prot, 202 - MAP_SHARED | MAP_FIXED, phys_fd, 203 - MMAP_OFFSET(offset) }; 175 + struct stub_syscall *sc; 204 176 205 - ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 206 - data, done); 177 + /* Compress with previous syscall if that is possible */ 178 + sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MUNMAP, addr); 179 + if (sc) { 180 + sc->mem.length += len; 181 + return 0; 182 + } 207 183 208 - return ret; 184 + sc = syscall_stub_alloc(mm_idp); 185 + sc->syscall = STUB_SYSCALL_MUNMAP; 186 + sc->mem.addr = addr; 187 + sc->mem.length = len; 188 + 189 + return 0; 209 190 } 210 191 211 - int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 212 - int done, void **data) 192 + int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, 193 + unsigned int prot) 213 194 { 214 - int ret; 215 - unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 216 - 0 }; 195 + struct stub_syscall *sc; 217 196 218 - ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 219 - data, done); 197 + /* Compress with previous syscall if that is possible */ 198 + sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MPROTECT, addr); 199 + if (sc && sc->mem.prot == prot) { 200 + sc->mem.length += len; 201 + return 0; 202 + } 220 203 221 - return ret; 222 - } 204 + sc = syscall_stub_alloc(mm_idp); 205 + sc->syscall = STUB_SYSCALL_MPROTECT; 206 + sc->mem.addr = addr; 207 + sc->mem.length = len; 208 + sc->mem.prot = prot; 223 209 224 - int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 225 - unsigned int prot, int done, void **data) 226 - { 227 - int ret; 228 - unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 229 - 230 - ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 231 - data, done); 232 - 233 - return ret; 210 + return 0; 234 211 }
+14 -110
arch/um/os-Linux/skas/process.c
··· 23 23 #include <skas.h> 24 24 #include <sysdep/stub.h> 25 25 #include <linux/threads.h> 26 + #include <timetravel.h> 26 27 #include "../internal.h" 27 28 28 29 int is_skas_winch(int pid, int fd, void *data) ··· 254 253 } 255 254 256 255 int userspace_pid[NR_CPUS]; 257 - int kill_userspace_mm[NR_CPUS]; 258 256 259 257 /** 260 258 * start_userspace() - prepare a new userspace process ··· 345 345 interrupt_end(); 346 346 347 347 while (1) { 348 - if (kill_userspace_mm[0]) 348 + time_travel_print_bc_msg(); 349 + 350 + current_mm_sync(); 351 + 352 + /* Flush out any pending syscalls */ 353 + err = syscall_stub_flush(current_mm_id()); 354 + if (err) { 355 + if (err == -ENOMEM) 356 + report_enomem(); 357 + 358 + printk(UM_KERN_ERR "%s - Error flushing stub syscalls: %d", 359 + __func__, -err); 349 360 fatal_sigsegv(); 361 + } 350 362 351 363 /* 352 364 * This can legitimately fail if the process loads a ··· 471 459 PT_SYSCALL_NR(regs->gp) = -1; 472 460 } 473 461 } 474 - } 475 - 476 - static unsigned long thread_regs[MAX_REG_NR]; 477 - static unsigned long thread_fp_regs[FP_SIZE]; 478 - 479 - static int __init init_thread_regs(void) 480 - { 481 - get_safe_registers(thread_regs, thread_fp_regs); 482 - /* Set parent's instruction pointer to start of clone-stub */ 483 - thread_regs[REGS_IP_INDEX] = STUB_CODE + 484 - (unsigned long) stub_clone_handler - 485 - (unsigned long) __syscall_stub_start; 486 - thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 487 - sizeof(void *); 488 - #ifdef __SIGNAL_FRAMESIZE 489 - thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; 490 - #endif 491 - return 0; 492 - } 493 - 494 - __initcall(init_thread_regs); 495 - 496 - int copy_context_skas0(unsigned long new_stack, int pid) 497 - { 498 - int err; 499 - unsigned long current_stack = current_stub_stack(); 500 - struct stub_data *data = (struct stub_data *) current_stack; 501 - struct stub_data *child_data = (struct stub_data *) new_stack; 502 - unsigned long long new_offset; 503 - int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset); 504 - 505 - /* 506 - * prepare offset and fd of child's stack as argument for parent's 507 - * and child's mmap2 calls 508 - */ 509 - *data = ((struct stub_data) { 510 - .offset = MMAP_OFFSET(new_offset), 511 - .fd = new_fd, 512 - .parent_err = -ESRCH, 513 - .child_err = 0, 514 - }); 515 - 516 - *child_data = ((struct stub_data) { 517 - .child_err = -ESRCH, 518 - }); 519 - 520 - err = ptrace_setregs(pid, thread_regs); 521 - if (err < 0) { 522 - err = -errno; 523 - printk(UM_KERN_ERR "%s : PTRACE_SETREGS failed, pid = %d, errno = %d\n", 524 - __func__, pid, -err); 525 - return err; 526 - } 527 - 528 - err = put_fp_registers(pid, thread_fp_regs); 529 - if (err < 0) { 530 - printk(UM_KERN_ERR "%s : put_fp_registers failed, pid = %d, err = %d\n", 531 - __func__, pid, err); 532 - return err; 533 - } 534 - 535 - /* 536 - * Wait, until parent has finished its work: read child's pid from 537 - * parent's stack, and check, if bad result. 538 - */ 539 - err = ptrace(PTRACE_CONT, pid, 0, 0); 540 - if (err) { 541 - err = -errno; 542 - printk(UM_KERN_ERR "Failed to continue new process, pid = %d, errno = %d\n", 543 - pid, errno); 544 - return err; 545 - } 546 - 547 - wait_stub_done(pid); 548 - 549 - pid = data->parent_err; 550 - if (pid < 0) { 551 - printk(UM_KERN_ERR "%s - stub-parent reports error %d\n", 552 - __func__, -pid); 553 - return pid; 554 - } 555 - 556 - /* 557 - * Wait, until child has finished too: read child's result from 558 - * child's stack and check it. 559 - */ 560 - wait_stub_done(pid); 561 - if (child_data->child_err != STUB_DATA) { 562 - printk(UM_KERN_ERR "%s - stub-child %d reports error %ld\n", 563 - __func__, pid, data->child_err); 564 - err = data->child_err; 565 - goto out_kill; 566 - } 567 - 568 - if (ptrace(PTRACE_SETOPTIONS, pid, NULL, 569 - (void *)PTRACE_O_TRACESYSGOOD) < 0) { 570 - err = -errno; 571 - printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n", 572 - __func__, errno); 573 - goto out_kill; 574 - } 575 - 576 - return pid; 577 - 578 - out_kill: 579 - os_kill_ptraced_process(pid, 1); 580 - return err; 581 462 } 582 463 583 464 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) ··· 589 684 void __switch_mm(struct mm_id *mm_idp) 590 685 { 591 686 userspace_pid[0] = mm_idp->u.pid; 592 - kill_userspace_mm[0] = mm_idp->kill; 593 687 }
+1
arch/um/os-Linux/start_up.c
··· 17 17 #include <sys/wait.h> 18 18 #include <sys/time.h> 19 19 #include <sys/resource.h> 20 + #include <asm/ldt.h> 20 21 #include <asm/unistd.h> 21 22 #include <init.h> 22 23 #include <os.h>
+1
arch/x86/Makefile.um
··· 9 9 # 10 10 ifeq ($(CONFIG_CC_IS_CLANG),y) 11 11 KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx 12 + KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json 12 13 KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2 13 14 endif 14 15
+2 -3
arch/x86/um/Makefile
··· 9 9 BITS := 64 10 10 endif 11 11 12 - obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \ 12 + obj-y = bugs_$(BITS).o delay.o fault.o \ 13 13 ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 14 - stub_$(BITS).o stub_segv.o \ 14 + stub_segv.o \ 15 15 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ 16 16 mem_$(BITS).o subarch.o os-Linux/ 17 17 ··· 31 31 32 32 subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o \ 33 33 ../lib/memmove_64.o ../lib/memset_64.o 34 - subarch-$(CONFIG_PREEMPTION) += ../entry/thunk_64.o 35 34 36 35 endif 37 36
-70
arch/x86/um/asm/mm_context.h
··· 1 - /* 2 - * Copyright (C) 2004 Fujitsu Siemens Computers GmbH 3 - * Licensed under the GPL 4 - * 5 - * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> 6 - */ 7 - 8 - #ifndef __ASM_LDT_H 9 - #define __ASM_LDT_H 10 - 11 - #include <linux/mutex.h> 12 - #include <asm/ldt.h> 13 - 14 - #define LDT_PAGES_MAX \ 15 - ((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE) 16 - #define LDT_ENTRIES_PER_PAGE \ 17 - (PAGE_SIZE/LDT_ENTRY_SIZE) 18 - #define LDT_DIRECT_ENTRIES \ 19 - ((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE) 20 - 21 - struct ldt_entry { 22 - __u32 a; 23 - __u32 b; 24 - }; 25 - 26 - typedef struct uml_ldt { 27 - int entry_count; 28 - struct mutex lock; 29 - union { 30 - struct ldt_entry * pages[LDT_PAGES_MAX]; 31 - struct ldt_entry entries[LDT_DIRECT_ENTRIES]; 32 - } u; 33 - } uml_ldt_t; 34 - 35 - #define LDT_entry_a(info) \ 36 - ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) 37 - 38 - #define LDT_entry_b(info) \ 39 - (((info)->base_addr & 0xff000000) | \ 40 - (((info)->base_addr & 0x00ff0000) >> 16) | \ 41 - ((info)->limit & 0xf0000) | \ 42 - (((info)->read_exec_only ^ 1) << 9) | \ 43 - ((info)->contents << 10) | \ 44 - (((info)->seg_not_present ^ 1) << 15) | \ 45 - ((info)->seg_32bit << 22) | \ 46 - ((info)->limit_in_pages << 23) | \ 47 - ((info)->useable << 20) | \ 48 - 0x7000) 49 - 50 - #define _LDT_empty(info) (\ 51 - (info)->base_addr == 0 && \ 52 - (info)->limit == 0 && \ 53 - (info)->contents == 0 && \ 54 - (info)->read_exec_only == 1 && \ 55 - (info)->seg_32bit == 0 && \ 56 - (info)->limit_in_pages == 0 && \ 57 - (info)->seg_not_present == 1 && \ 58 - (info)->useable == 0 ) 59 - 60 - #ifdef CONFIG_X86_64 61 - #define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) 62 - #else 63 - #define LDT_empty(info) (_LDT_empty(info)) 64 - #endif 65 - 66 - struct uml_arch_mm_context { 67 - uml_ldt_t ldt; 68 - }; 69 - 70 - #endif
-380
arch/x86/um/ldt.c
··· 1 - /* 2 - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 - * Licensed under the GPL 4 - */ 5 - 6 - #include <linux/mm.h> 7 - #include <linux/sched.h> 8 - #include <linux/slab.h> 9 - #include <linux/syscalls.h> 10 - #include <linux/uaccess.h> 11 - #include <asm/unistd.h> 12 - #include <os.h> 13 - #include <skas.h> 14 - #include <sysdep/tls.h> 15 - 16 - static inline int modify_ldt (int func, void *ptr, unsigned long bytecount) 17 - { 18 - return syscall(__NR_modify_ldt, func, ptr, bytecount); 19 - } 20 - 21 - static long write_ldt_entry(struct mm_id *mm_idp, int func, 22 - struct user_desc *desc, void **addr, int done) 23 - { 24 - long res; 25 - void *stub_addr; 26 - 27 - BUILD_BUG_ON(sizeof(*desc) % sizeof(long)); 28 - 29 - res = syscall_stub_data(mm_idp, (unsigned long *)desc, 30 - sizeof(*desc) / sizeof(long), 31 - addr, &stub_addr); 32 - if (!res) { 33 - unsigned long args[] = { func, 34 - (unsigned long)stub_addr, 35 - sizeof(*desc), 36 - 0, 0, 0 }; 37 - res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, 38 - 0, addr, done); 39 - } 40 - 41 - return res; 42 - } 43 - 44 - /* 45 - * In skas mode, we hold our own ldt data in UML. 46 - * Thus, the code implementing sys_modify_ldt_skas 47 - * is very similar to (and mostly stolen from) sys_modify_ldt 48 - * for arch/i386/kernel/ldt.c 49 - * The routines copied and modified in part are: 50 - * - read_ldt 51 - * - read_default_ldt 52 - * - write_ldt 53 - * - sys_modify_ldt_skas 54 - */ 55 - 56 - static int read_ldt(void __user * ptr, unsigned long bytecount) 57 - { 58 - int i, err = 0; 59 - unsigned long size; 60 - uml_ldt_t *ldt = &current->mm->context.arch.ldt; 61 - 62 - if (!ldt->entry_count) 63 - goto out; 64 - if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) 65 - bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; 66 - err = bytecount; 67 - 68 - mutex_lock(&ldt->lock); 69 - if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { 70 - size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; 71 - if (size > bytecount) 72 - size = bytecount; 73 - if (copy_to_user(ptr, ldt->u.entries, size)) 74 - err = -EFAULT; 75 - bytecount -= size; 76 - ptr += size; 77 - } 78 - else { 79 - for (i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount; 80 - i++) { 81 - size = PAGE_SIZE; 82 - if (size > bytecount) 83 - size = bytecount; 84 - if (copy_to_user(ptr, ldt->u.pages[i], size)) { 85 - err = -EFAULT; 86 - break; 87 - } 88 - bytecount -= size; 89 - ptr += size; 90 - } 91 - } 92 - mutex_unlock(&ldt->lock); 93 - 94 - if (bytecount == 0 || err == -EFAULT) 95 - goto out; 96 - 97 - if (clear_user(ptr, bytecount)) 98 - err = -EFAULT; 99 - 100 - out: 101 - return err; 102 - } 103 - 104 - static int read_default_ldt(void __user * ptr, unsigned long bytecount) 105 - { 106 - int err; 107 - 108 - if (bytecount > 5*LDT_ENTRY_SIZE) 109 - bytecount = 5*LDT_ENTRY_SIZE; 110 - 111 - err = bytecount; 112 - /* 113 - * UML doesn't support lcall7 and lcall27. 114 - * So, we don't really have a default ldt, but emulate 115 - * an empty ldt of common host default ldt size. 116 - */ 117 - if (clear_user(ptr, bytecount)) 118 - err = -EFAULT; 119 - 120 - return err; 121 - } 122 - 123 - static int write_ldt(void __user * ptr, unsigned long bytecount, int func) 124 - { 125 - uml_ldt_t *ldt = &current->mm->context.arch.ldt; 126 - struct mm_id * mm_idp = &current->mm->context.id; 127 - int i, err; 128 - struct user_desc ldt_info; 129 - struct ldt_entry entry0, *ldt_p; 130 - void *addr = NULL; 131 - 132 - err = -EINVAL; 133 - if (bytecount != sizeof(ldt_info)) 134 - goto out; 135 - err = -EFAULT; 136 - if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) 137 - goto out; 138 - 139 - err = -EINVAL; 140 - if (ldt_info.entry_number >= LDT_ENTRIES) 141 - goto out; 142 - if (ldt_info.contents == 3) { 143 - if (func == 1) 144 - goto out; 145 - if (ldt_info.seg_not_present == 0) 146 - goto out; 147 - } 148 - 149 - mutex_lock(&ldt->lock); 150 - 151 - err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); 152 - if (err) 153 - goto out_unlock; 154 - 155 - if (ldt_info.entry_number >= ldt->entry_count && 156 - ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { 157 - for (i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; 158 - i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; 159 - i++) { 160 - if (i == 0) 161 - memcpy(&entry0, ldt->u.entries, 162 - sizeof(entry0)); 163 - ldt->u.pages[i] = (struct ldt_entry *) 164 - __get_free_page(GFP_KERNEL|__GFP_ZERO); 165 - if (!ldt->u.pages[i]) { 166 - err = -ENOMEM; 167 - /* Undo the change in host */ 168 - memset(&ldt_info, 0, sizeof(ldt_info)); 169 - write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); 170 - goto out_unlock; 171 - } 172 - if (i == 0) { 173 - memcpy(ldt->u.pages[0], &entry0, 174 - sizeof(entry0)); 175 - memcpy(ldt->u.pages[0]+1, ldt->u.entries+1, 176 - sizeof(entry0)*(LDT_DIRECT_ENTRIES-1)); 177 - } 178 - ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE; 179 - } 180 - } 181 - if (ldt->entry_count <= ldt_info.entry_number) 182 - ldt->entry_count = ldt_info.entry_number + 1; 183 - 184 - if (ldt->entry_count <= LDT_DIRECT_ENTRIES) 185 - ldt_p = ldt->u.entries + ldt_info.entry_number; 186 - else 187 - ldt_p = ldt->u.pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] + 188 - ldt_info.entry_number%LDT_ENTRIES_PER_PAGE; 189 - 190 - if (ldt_info.base_addr == 0 && ldt_info.limit == 0 && 191 - (func == 1 || LDT_empty(&ldt_info))) { 192 - ldt_p->a = 0; 193 - ldt_p->b = 0; 194 - } 195 - else{ 196 - if (func == 1) 197 - ldt_info.useable = 0; 198 - ldt_p->a = LDT_entry_a(&ldt_info); 199 - ldt_p->b = LDT_entry_b(&ldt_info); 200 - } 201 - err = 0; 202 - 203 - out_unlock: 204 - mutex_unlock(&ldt->lock); 205 - out: 206 - return err; 207 - } 208 - 209 - static long do_modify_ldt_skas(int func, void __user *ptr, 210 - unsigned long bytecount) 211 - { 212 - int ret = -ENOSYS; 213 - 214 - switch (func) { 215 - case 0: 216 - ret = read_ldt(ptr, bytecount); 217 - break; 218 - case 1: 219 - case 0x11: 220 - ret = write_ldt(ptr, bytecount, func); 221 - break; 222 - case 2: 223 - ret = read_default_ldt(ptr, bytecount); 224 - break; 225 - } 226 - return ret; 227 - } 228 - 229 - static DEFINE_SPINLOCK(host_ldt_lock); 230 - static short dummy_list[9] = {0, -1}; 231 - static short * host_ldt_entries = NULL; 232 - 233 - static void ldt_get_host_info(void) 234 - { 235 - long ret; 236 - struct ldt_entry * ldt; 237 - short *tmp; 238 - int i, size, k, order; 239 - 240 - spin_lock(&host_ldt_lock); 241 - 242 - if (host_ldt_entries != NULL) { 243 - spin_unlock(&host_ldt_lock); 244 - return; 245 - } 246 - host_ldt_entries = dummy_list+1; 247 - 248 - spin_unlock(&host_ldt_lock); 249 - 250 - for (i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++) 251 - ; 252 - 253 - ldt = (struct ldt_entry *) 254 - __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); 255 - if (ldt == NULL) { 256 - printk(KERN_ERR "ldt_get_host_info: couldn't allocate buffer " 257 - "for host ldt\n"); 258 - return; 259 - } 260 - 261 - ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE); 262 - if (ret < 0) { 263 - printk(KERN_ERR "ldt_get_host_info: couldn't read host ldt\n"); 264 - goto out_free; 265 - } 266 - if (ret == 0) { 267 - /* default_ldt is active, simply write an empty entry 0 */ 268 - host_ldt_entries = dummy_list; 269 - goto out_free; 270 - } 271 - 272 - for (i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++) { 273 - if (ldt[i].a != 0 || ldt[i].b != 0) 274 - size++; 275 - } 276 - 277 - if (size < ARRAY_SIZE(dummy_list)) 278 - host_ldt_entries = dummy_list; 279 - else { 280 - size = (size + 1) * sizeof(dummy_list[0]); 281 - tmp = kmalloc(size, GFP_KERNEL); 282 - if (tmp == NULL) { 283 - printk(KERN_ERR "ldt_get_host_info: couldn't allocate " 284 - "host ldt list\n"); 285 - goto out_free; 286 - } 287 - host_ldt_entries = tmp; 288 - } 289 - 290 - for (i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++) { 291 - if (ldt[i].a != 0 || ldt[i].b != 0) 292 - host_ldt_entries[k++] = i; 293 - } 294 - host_ldt_entries[k] = -1; 295 - 296 - out_free: 297 - free_pages((unsigned long)ldt, order); 298 - } 299 - 300 - long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) 301 - { 302 - struct user_desc desc; 303 - short * num_p; 304 - int i; 305 - long page, err=0; 306 - void *addr = NULL; 307 - 308 - 309 - mutex_init(&new_mm->arch.ldt.lock); 310 - 311 - if (!from_mm) { 312 - memset(&desc, 0, sizeof(desc)); 313 - /* 314 - * Now we try to retrieve info about the ldt, we 315 - * inherited from the host. All ldt-entries found 316 - * will be reset in the following loop 317 - */ 318 - ldt_get_host_info(); 319 - for (num_p=host_ldt_entries; *num_p != -1; num_p++) { 320 - desc.entry_number = *num_p; 321 - err = write_ldt_entry(&new_mm->id, 1, &desc, 322 - &addr, *(num_p + 1) == -1); 323 - if (err) 324 - break; 325 - } 326 - new_mm->arch.ldt.entry_count = 0; 327 - 328 - goto out; 329 - } 330 - 331 - /* 332 - * Our local LDT is used to supply the data for 333 - * modify_ldt(READLDT), if PTRACE_LDT isn't available, 334 - * i.e., we have to use the stub for modify_ldt, which 335 - * can't handle the big read buffer of up to 64kB. 336 - */ 337 - mutex_lock(&from_mm->arch.ldt.lock); 338 - if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES) 339 - memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries, 340 - sizeof(new_mm->arch.ldt.u.entries)); 341 - else { 342 - i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; 343 - while (i-->0) { 344 - page = __get_free_page(GFP_KERNEL|__GFP_ZERO); 345 - if (!page) { 346 - err = -ENOMEM; 347 - break; 348 - } 349 - new_mm->arch.ldt.u.pages[i] = 350 - (struct ldt_entry *) page; 351 - memcpy(new_mm->arch.ldt.u.pages[i], 352 - from_mm->arch.ldt.u.pages[i], PAGE_SIZE); 353 - } 354 - } 355 - new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count; 356 - mutex_unlock(&from_mm->arch.ldt.lock); 357 - 358 - out: 359 - return err; 360 - } 361 - 362 - 363 - void free_ldt(struct mm_context *mm) 364 - { 365 - int i; 366 - 367 - if (mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) { 368 - i = mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; 369 - while (i-- > 0) 370 - free_page((long) mm->arch.ldt.u.pages[i]); 371 - } 372 - mm->arch.ldt.entry_count = 0; 373 - } 374 - 375 - SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , 376 - unsigned long , bytecount) 377 - { 378 - /* See non-um modify_ldt() for why we do this cast */ 379 - return (unsigned int)do_modify_ldt_skas(func, ptr, bytecount); 380 - }
+1 -1
arch/x86/um/shared/sysdep/stub.h
··· 12 12 #endif 13 13 14 14 extern void stub_segv_handler(int, siginfo_t *, void *); 15 - extern void stub_clone_handler(void); 15 + extern void stub_syscall_handler(void);
+23 -24
arch/x86/um/shared/sysdep/stub_32.h
··· 6 6 #ifndef __SYSDEP_STUB_H 7 7 #define __SYSDEP_STUB_H 8 8 9 + #include <stddef.h> 9 10 #include <asm/ptrace.h> 10 11 #include <generated/asm-offsets.h> 11 12 ··· 80 79 return ret; 81 80 } 82 81 82 + static __always_inline long stub_syscall6(long syscall, long arg1, long arg2, 83 + long arg3, long arg4, long arg5, 84 + long arg6) 85 + { 86 + struct syscall_args { 87 + int ebx, ebp; 88 + } args = { arg1, arg6 }; 89 + long ret; 90 + 91 + __asm__ volatile ("pushl %%ebp;" 92 + "movl 0x4(%%ebx),%%ebp;" 93 + "movl (%%ebx),%%ebx;" 94 + "int $0x80;" 95 + "popl %%ebp" 96 + : "=a" (ret) 97 + : "0" (syscall), "b" (&args), 98 + "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5) 99 + : "memory"); 100 + 101 + return ret; 102 + } 103 + 83 104 static __always_inline void trap_myself(void) 84 105 { 85 106 __asm("int3"); 86 - } 87 - 88 - static __always_inline void remap_stack_and_trap(void) 89 - { 90 - __asm__ volatile ( 91 - "movl %%esp,%%ebx ;" 92 - "andl %0,%%ebx ;" 93 - "movl %1,%%eax ;" 94 - "movl %%ebx,%%edi ; addl %2,%%edi ; movl (%%edi),%%edi ;" 95 - "movl %%ebx,%%ebp ; addl %3,%%ebp ; movl (%%ebp),%%ebp ;" 96 - "int $0x80 ;" 97 - "addl %4,%%ebx ; movl %%eax, (%%ebx) ;" 98 - "int $3" 99 - : : 100 - "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)), 101 - "g" (STUB_MMAP_NR), 102 - "g" (UML_STUB_FIELD_FD), 103 - "g" (UML_STUB_FIELD_OFFSET), 104 - "g" (UML_STUB_FIELD_CHILD_ERR), 105 - "c" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE), 106 - "d" (PROT_READ | PROT_WRITE), 107 - "S" (MAP_FIXED | MAP_SHARED) 108 - : 109 - "memory"); 110 107 } 111 108 112 109 static __always_inline void *get_stub_data(void)
+17 -26
arch/x86/um/shared/sysdep/stub_64.h
··· 6 6 #ifndef __SYSDEP_STUB_H 7 7 #define __SYSDEP_STUB_H 8 8 9 + #include <stddef.h> 9 10 #include <sysdep/ptrace_user.h> 10 11 #include <generated/asm-offsets.h> 11 12 #include <linux/stddef.h> ··· 80 79 return ret; 81 80 } 82 81 82 + static __always_inline long stub_syscall6(long syscall, long arg1, long arg2, 83 + long arg3, long arg4, long arg5, 84 + long arg6) 85 + { 86 + long ret; 87 + 88 + __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9 ; " 89 + __syscall 90 + : "=a" (ret) 91 + : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), 92 + "g" (arg4), "g" (arg5), "g" (arg6) 93 + : __syscall_clobber, "r10", "r8", "r9"); 94 + 95 + return ret; 96 + } 97 + 83 98 static __always_inline void trap_myself(void) 84 99 { 85 100 __asm("int3"); 86 - } 87 - 88 - static __always_inline void remap_stack_and_trap(void) 89 - { 90 - __asm__ volatile ( 91 - "movq %0,%%rax ;" 92 - "movq %%rsp,%%rdi ;" 93 - "andq %1,%%rdi ;" 94 - "movq %2,%%r10 ;" 95 - "movq %%rdi,%%r8 ; addq %3,%%r8 ; movq (%%r8),%%r8 ;" 96 - "movq %%rdi,%%r9 ; addq %4,%%r9 ; movq (%%r9),%%r9 ;" 97 - __syscall ";" 98 - "movq %%rsp,%%rdi ; andq %1,%%rdi ;" 99 - "addq %5,%%rdi ; movq %%rax, (%%rdi) ;" 100 - "int3" 101 - : : 102 - "g" (STUB_MMAP_NR), 103 - "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)), 104 - "g" (MAP_FIXED | MAP_SHARED), 105 - "g" (UML_STUB_FIELD_FD), 106 - "g" (UML_STUB_FIELD_OFFSET), 107 - "g" (UML_STUB_FIELD_CHILD_ERR), 108 - "S" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE), 109 - "d" (PROT_READ | PROT_WRITE) 110 - : 111 - __syscall_clobber, "r10", "r8", "r9"); 112 101 } 113 102 114 103 static __always_inline void *get_stub_data(void)
-56
arch/x86/um/stub_32.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <as-layout.h> 3 - 4 - .section .__syscall_stub, "ax" 5 - 6 - .globl batch_syscall_stub 7 - batch_syscall_stub: 8 - /* %esp comes in as "top of page" */ 9 - mov %esp, %ecx 10 - /* %esp has pointer to first operation */ 11 - add $8, %esp 12 - again: 13 - /* load length of additional data */ 14 - mov 0x0(%esp), %eax 15 - 16 - /* if(length == 0) : end of list */ 17 - /* write possible 0 to header */ 18 - mov %eax, 0x4(%ecx) 19 - cmpl $0, %eax 20 - jz done 21 - 22 - /* save current pointer */ 23 - mov %esp, 0x4(%ecx) 24 - 25 - /* skip additional data */ 26 - add %eax, %esp 27 - 28 - /* load syscall-# */ 29 - pop %eax 30 - 31 - /* load syscall params */ 32 - pop %ebx 33 - pop %ecx 34 - pop %edx 35 - pop %esi 36 - pop %edi 37 - pop %ebp 38 - 39 - /* execute syscall */ 40 - int $0x80 41 - 42 - /* restore top of page pointer in %ecx */ 43 - mov %esp, %ecx 44 - andl $(~UM_KERN_PAGE_SIZE) + 1, %ecx 45 - 46 - /* check return value */ 47 - pop %ebx 48 - cmp %ebx, %eax 49 - je again 50 - 51 - done: 52 - /* save return value */ 53 - mov %eax, (%ecx) 54 - 55 - /* stop */ 56 - int3
-50
arch/x86/um/stub_64.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <as-layout.h> 3 - 4 - .section .__syscall_stub, "ax" 5 - .globl batch_syscall_stub 6 - batch_syscall_stub: 7 - /* %rsp has the pointer to first operation */ 8 - mov %rsp, %rbx 9 - add $0x10, %rsp 10 - again: 11 - /* load length of additional data */ 12 - mov 0x0(%rsp), %rax 13 - 14 - /* if(length == 0) : end of list */ 15 - /* write possible 0 to header */ 16 - mov %rax, 8(%rbx) 17 - cmp $0, %rax 18 - jz done 19 - 20 - /* save current pointer */ 21 - mov %rsp, 8(%rbx) 22 - 23 - /* skip additional data */ 24 - add %rax, %rsp 25 - 26 - /* load syscall-# */ 27 - pop %rax 28 - 29 - /* load syscall params */ 30 - pop %rdi 31 - pop %rsi 32 - pop %rdx 33 - pop %r10 34 - pop %r8 35 - pop %r9 36 - 37 - /* execute syscall */ 38 - syscall 39 - 40 - /* check return value */ 41 - pop %rcx 42 - cmp %rcx, %rax 43 - je again 44 - 45 - done: 46 - /* save return value */ 47 - mov %rax, (%rbx) 48 - 49 - /* stop */ 50 - int3
+1
arch/x86/um/tls_32.c
··· 11 11 #include <os.h> 12 12 #include <skas.h> 13 13 #include <sysdep/tls.h> 14 + #include <asm/desc.h> 14 15 15 16 /* 16 17 * If needed we can detect when it's uninitialized.
+4 -3
fs/hostfs/hostfs.h
··· 63 63 struct hostfs_timespec atime, mtime, ctime; 64 64 unsigned int blksize; 65 65 unsigned long long blocks; 66 - unsigned int maj; 67 - unsigned int min; 68 - dev_t dev; 66 + struct { 67 + unsigned int maj; 68 + unsigned int min; 69 + } rdev, dev; 69 70 }; 70 71 71 72 extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
+7 -4
fs/hostfs/hostfs_kern.c
··· 532 532 static int hostfs_inode_set(struct inode *ino, void *data) 533 533 { 534 534 struct hostfs_stat *st = data; 535 - dev_t rdev; 535 + dev_t dev, rdev; 536 536 537 537 /* Reencode maj and min with the kernel encoding.*/ 538 - rdev = MKDEV(st->maj, st->min); 538 + rdev = MKDEV(st->rdev.maj, st->rdev.min); 539 + dev = MKDEV(st->dev.maj, st->dev.min); 539 540 540 541 switch (st->mode & S_IFMT) { 541 542 case S_IFLNK: ··· 562 561 return -EIO; 563 562 } 564 563 565 - HOSTFS_I(ino)->dev = st->dev; 564 + HOSTFS_I(ino)->dev = dev; 566 565 ino->i_ino = st->ino; 567 566 ino->i_mode = st->mode; 568 567 return hostfs_inode_update(ino, st); ··· 571 570 static int hostfs_inode_test(struct inode *inode, void *data) 572 571 { 573 572 const struct hostfs_stat *st = data; 573 + dev_t dev = MKDEV(st->dev.maj, st->dev.min); 574 574 575 - return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev; 575 + return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == dev; 576 576 } 577 577 578 578 static struct inode *hostfs_iget(struct super_block *sb, char *name) ··· 1042 1040 1043 1041 module_init(init_hostfs) 1044 1042 module_exit(exit_hostfs) 1043 + MODULE_DESCRIPTION("User-Mode Linux Host filesystem"); 1045 1044 MODULE_LICENSE("GPL");
+4 -3
fs/hostfs/hostfs_user.c
··· 34 34 p->mtime.tv_nsec = 0; 35 35 p->blksize = buf->st_blksize; 36 36 p->blocks = buf->st_blocks; 37 - p->maj = os_major(buf->st_rdev); 38 - p->min = os_minor(buf->st_rdev); 39 - p->dev = buf->st_dev; 37 + p->rdev.maj = os_major(buf->st_rdev); 38 + p->rdev.min = os_minor(buf->st_rdev); 39 + p->dev.maj = os_major(buf->st_dev); 40 + p->dev.min = os_minor(buf->st_dev); 40 41 } 41 42 42 43 int stat_file(const char *path, struct hostfs_stat *p, int fd)
+176 -14
include/uapi/linux/um_timetravel.h
··· 1 + /* SPDX-License-Identifier: BSD-3-Clause */ 1 2 /* 2 - * Permission to use, copy, modify, and/or distribute this software for any 3 - * purpose with or without fee is hereby granted, provided that the above 4 - * copyright notice and this permission notice appear in all copies. 5 - * 6 - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 11 - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 12 - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 - * 14 - * Copyright (C) 2019 Intel Corporation 3 + * Copyright (C) 2019 - 2023 Intel Corporation 15 4 */ 16 5 #ifndef _UAPI_LINUX_UM_TIMETRAVEL_H 17 6 #define _UAPI_LINUX_UM_TIMETRAVEL_H ··· 39 50 __u64 time; 40 51 }; 41 52 53 + /* max number of file descriptors that can be sent/received in a message */ 54 + #define UM_TIMETRAVEL_MAX_FDS 2 55 + 56 + /** 57 + * enum um_timetravel_shared_mem_fds - fds sent in ACK message for START message 58 + */ 59 + enum um_timetravel_shared_mem_fds { 60 + /** 61 + * @UM_TIMETRAVEL_SHARED_MEMFD: Index of the shared memory file 62 + * descriptor in the control message 63 + */ 64 + UM_TIMETRAVEL_SHARED_MEMFD, 65 + /** 66 + * @UM_TIMETRAVEL_SHARED_LOGFD: Index of the logging file descriptor 67 + * in the control message 68 + */ 69 + UM_TIMETRAVEL_SHARED_LOGFD, 70 + UM_TIMETRAVEL_SHARED_MAX_FDS, 71 + }; 72 + 73 + /** 74 + * enum um_timetravel_start_ack - ack-time mask for start message 75 + */ 76 + enum um_timetravel_start_ack { 77 + /** 78 + * @UM_TIMETRAVEL_START_ACK_ID: client ID that controller allocated. 79 + */ 80 + UM_TIMETRAVEL_START_ACK_ID = 0xffff, 81 + }; 82 + 42 83 /** 43 84 * enum um_timetravel_ops - Operation codes 44 85 */ ··· 76 57 /** 77 58 * @UM_TIMETRAVEL_ACK: response (ACK) to any previous message, 78 59 * this usually doesn't carry any data in the 'time' field 79 - * unless otherwise specified below 60 + * unless otherwise specified below, note: while using shared 61 + * memory no ACK for WAIT and RUN messages, for more info see 62 + * &struct um_timetravel_schedshm. 80 63 */ 81 64 UM_TIMETRAVEL_ACK = 0, 82 65 ··· 144 123 * the simulation. 145 124 */ 146 125 UM_TIMETRAVEL_GET_TOD = 8, 126 + 127 + /** 128 + * @UM_TIMETRAVEL_BROADCAST: Send/Receive a broadcast message. 129 + * This message can be used to sync all components in the system 130 + * with a single message, if the calender gets the message, the 131 + * calender broadcast the message to all components, and if a 132 + * component receives it it should act based on it e.g print a 133 + * message to it's log system. 134 + * (calendar <-> host) 135 + */ 136 + UM_TIMETRAVEL_BROADCAST = 9, 147 137 }; 148 138 139 + /* version of struct um_timetravel_schedshm */ 140 + #define UM_TIMETRAVEL_SCHEDSHM_VERSION 2 141 + 142 + /** 143 + * enum um_timetravel_schedshm_cap - time travel capabilities of every client 144 + * 145 + * These flags must be set immediately after processing the ACK to 146 + * the START message, before sending any message to the controller. 147 + */ 148 + enum um_timetravel_schedshm_cap { 149 + /** 150 + * @UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE: client can read current time 151 + * update internal time request to shared memory and read 152 + * free until and send no Ack on RUN and doesn't expect ACK on 153 + * WAIT. 154 + */ 155 + UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE = 0x1, 156 + }; 157 + 158 + /** 159 + * enum um_timetravel_schedshm_flags - time travel flags of every client 160 + */ 161 + enum um_timetravel_schedshm_flags { 162 + /** 163 + * @UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN: client has a request to run. 164 + * It's set by client when it has a request to run, if (and only 165 + * if) the @running_id points to a client that is able to use 166 + * shared memory, i.e. has %UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE 167 + * (this includes the client itself). Otherwise, a message must 168 + * be used. 169 + */ 170 + UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN = 0x1, 171 + }; 172 + 173 + /** 174 + * DOC: Time travel shared memory overview 175 + * 176 + * The main purpose of the shared memory is to avoid all time travel message 177 + * that don't need any action, for example current time can be held in shared 178 + * memory without the need of any client to send a message UM_TIMETRAVEL_GET 179 + * in order to know what's the time. 180 + * 181 + * Since this is shared memory with all clients and controller and controller 182 + * creates the shared memory space, all time values are absolute to controller 183 + * time. So first time client connects to shared memory mode it should take the 184 + * current_time value in shared memory and keep it internally as a diff to 185 + * shared memory times, and once shared memory is initialized, any interaction 186 + * with the controller must happen in the controller time domain, including any 187 + * messages (for clients that are not using shared memory, the controller will 188 + * handle an offset and make the clients think they start at time zero.) 189 + * 190 + * Along with the shared memory file descriptor is sent to the client a logging 191 + * file descriptor, to have all logs related to shared memory, 192 + * logged into one place. note: to have all logs synced into log file at write, 193 + * file should be flushed (fflush) after writing to it. 194 + * 195 + * To avoid memory corruption, we define below for each field who can write to 196 + * it at what time, defined in the structure fields. 197 + * 198 + * To avoid having to pack this struct, all fields in it must be naturally aligned 199 + * (i.e. aligned to their size). 200 + */ 201 + 202 + /** 203 + * union um_timetravel_schedshm_client - UM time travel client struct 204 + * 205 + * Every entity using the shared memory including the controller has a place in 206 + * the um_timetravel_schedshm clients array, that holds info related to the client 207 + * using the shared memory, and can be set only by the client after it gets the 208 + * fd memory. 209 + * 210 + * @capa: bit fields with client capabilities see 211 + * &enum um_timetravel_schedshm_cap, set by client once after getting the 212 + * shared memory file descriptor. 213 + * @flags: bit fields for flags see &enum um_timetravel_schedshm_flags for doc. 214 + * @req_time: request time to run, set by client on every request it needs. 215 + * @name: unique id sent to the controller by client with START message. 216 + */ 217 + union um_timetravel_schedshm_client { 218 + struct { 219 + __u32 capa; 220 + __u32 flags; 221 + __u64 req_time; 222 + __u64 name; 223 + }; 224 + char reserve[128]; /* reserved for future usage */ 225 + }; 226 + 227 + /** 228 + * struct um_timetravel_schedshm - UM time travel shared memory struct 229 + * 230 + * @hdr: header fields: 231 + * @version: Current version struct UM_TIMETRAVEL_SCHEDSHM_VERSION, 232 + * set by controller once at init, clients must check this after mapping 233 + * and work without shared memory if they cannot handle the indicated 234 + * version. 235 + * @len: Length of all the memory including header (@hdr), clients should once 236 + * per connection first mmap the header and take the length (@len) to remap the entire size. 237 + * This is done in order to support dynamic struct size letting number of 238 + * clients be dynamic based on controller support. 239 + * @free_until: Stores the next request to run by any client, in order for the 240 + * current client to know how long it can still run. A client needs to (at 241 + * least) reload this value immediately after communicating with any other 242 + * client, since the controller will update this field when a new request 243 + * is made by any client. Clients also must update this value when they 244 + * insert/update an own request into the shared memory while not running 245 + * themselves, and the new request is before than the current value. 246 + * current_time: Current time, can only be set by the client in running state 247 + * (indicated by @running_id), though that client may only run until @free_until, 248 + * so it must remain smaller than @free_until. 249 + * @running_id: The current client in state running, set before a client is 250 + * notified that it's now running. 251 + * @max_clients: size of @clients array, set once at init by the controller. 252 + * @clients: clients array see &union um_timetravel_schedshm_client for doc, 253 + * set only by client. 254 + */ 255 + struct um_timetravel_schedshm { 256 + union { 257 + struct { 258 + __u32 version; 259 + __u32 len; 260 + __u64 free_until; 261 + __u64 current_time; 262 + __u16 running_id; 263 + __u16 max_clients; 264 + }; 265 + char hdr[4096]; /* align to 4K page size */ 266 + }; 267 + union um_timetravel_schedshm_client clients[]; 268 + }; 149 269 #endif /* _UAPI_LINUX_UM_TIMETRAVEL_H */
+1 -1
rust/Makefile
··· 426 426 $(obj)/core.o: private rustc_target_flags = $(core-cfgs) 427 427 $(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs FORCE 428 428 +$(call if_changed_dep,rustc_library) 429 - ifdef CONFIG_X86_64 429 + ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),) 430 430 $(obj)/core.o: scripts/target.json 431 431 endif 432 432
+1 -1
scripts/Makefile
··· 12 12 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder 13 13 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen 14 14 15 - ifdef CONFIG_X86_64 15 + ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),) 16 16 always-$(CONFIG_RUST) += target.json 17 17 filechk_rust_target = $< < include/config/auto.conf 18 18
+17
scripts/generate_rust_target.rs
··· 169 169 ts.push("features", features); 170 170 ts.push("llvm-target", "x86_64-linux-gnu"); 171 171 ts.push("target-pointer-width", "64"); 172 + } else if cfg.has("X86_32") { 173 + // This only works on UML, as i386 otherwise needs regparm support in rustc 174 + if !cfg.has("UML") { 175 + panic!("32-bit x86 only works under UML"); 176 + } 177 + ts.push("arch", "x86"); 178 + ts.push( 179 + "data-layout", 180 + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", 181 + ); 182 + let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string(); 183 + if cfg.has("MITIGATION_RETPOLINE") { 184 + features += ",+retpoline-external-thunk"; 185 + } 186 + ts.push("features", features); 187 + ts.push("llvm-target", "i386-unknown-linux-gnu"); 188 + ts.push("target-pointer-width", "32"); 172 189 } else if cfg.has("LOONGARCH") { 173 190 panic!("loongarch uses the builtin rustc loongarch64-unknown-none-softfloat target"); 174 191 } else {