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

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

Pull UML updates from Johannes Berg:
"Apart from the usual small churn, we have

- initial SMP support (only kernel)

- major vDSO cleanups (and fixes for 32-bit)"

* tag 'uml-for-linux-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux: (33 commits)
um: Disable KASAN_INLINE when STATIC_LINK is selected
um: Don't rename vmap to kernel_vmap
um: drivers: virtio: use string choices helper
um: Always set up AT_HWCAP and AT_PLATFORM
x86/um: Remove FIXADDR_USER_START and FIXADDR_USE_END
um: Remove __access_ok_vsyscall()
um: Remove redundant range check from __access_ok_vsyscall()
um: Remove fixaddr_user_init()
x86/um: Drop gate area handling
x86/um: Do not inherit vDSO from host
um: Split out default elf_aux_hwcap
x86/um: Move ELF_PLATFORM fallback to x86-specific code
um: Split out default elf_aux_platform
um: Avoid circular dependency on asm-offsets in pgtable.h
um: Enable SMP support on x86
asm-generic: percpu: Add assembly guard
um: vdso: Remove getcpu support on x86
um: Add initial SMP support
um: Define timers on a per-CPU basis
um: Determine sleep based on need_resched()
...

+972 -865
+1 -1
Documentation/features/core/generic-idle-thread/arch-support.txt
··· 24 24 | s390: | ok | 25 25 | sh: | ok | 26 26 | sparc: | ok | 27 - | um: | TODO | 27 + | um: | ok | 28 28 | x86: | ok | 29 29 | xtensa: | ok | 30 30 -----------------------
+44 -9
arch/um/Kconfig
··· 5 5 config UML 6 6 bool 7 7 default y 8 + select ARCH_DISABLE_KASAN_INLINE if STATIC_LINK 8 9 select ARCH_NEEDS_DEFER_KASAN if STATIC_LINK 9 10 select ARCH_WANTS_DYNAMIC_TASK_STRUCT 10 11 select ARCH_HAS_CACHE_LINE_SIZE ··· 29 28 select OF_EARLY_FLATTREE if OF 30 29 select GENERIC_IRQ_SHOW 31 30 select GENERIC_CPU_DEVICES 31 + select GENERIC_SMP_IDLE_THREAD 32 32 select HAVE_GCC_PLUGINS 33 33 select ARCH_SUPPORTS_LTO_CLANG 34 34 select ARCH_SUPPORTS_LTO_CLANG_THIN ··· 83 81 int 84 82 default 100 85 83 86 - config NR_CPUS 84 + config UML_SUBARCH_SUPPORTS_SMP 85 + bool 86 + 87 + config SMP 88 + bool "Symmetric multi-processing support" 89 + default n 90 + depends on UML_SUBARCH_SUPPORTS_SMP 91 + help 92 + This option enables UML SMP support. 93 + 94 + With this enabled, users can tell UML to start multiple virtual 95 + processors. Each virtual processor is represented as a separate 96 + host thread. 97 + 98 + In UML, kthreads and normal threads (when running in kernel mode) 99 + can be scheduled and executed simultaneously on different virtual 100 + processors. However, the userspace code of normal threads still 101 + runs within their respective single-threaded stubs. 102 + 103 + That is, SMP support is available both within the kernel and 104 + across different processes, but remains limited within threads 105 + of the same process in userspace. 106 + 107 + config NR_CPUS_RANGE_BEGIN 87 108 int 88 - range 1 1 89 - default 1 109 + default 1 if !SMP 110 + default 2 111 + 112 + config NR_CPUS_RANGE_END 113 + int 114 + default 1 if !SMP 115 + default 64 116 + 117 + config NR_CPUS_DEFAULT 118 + int 119 + default 1 if !SMP 120 + default 2 121 + 122 + config NR_CPUS 123 + int "Maximum number of CPUs" if SMP 124 + range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END 125 + default NR_CPUS_DEFAULT 90 126 91 127 source "arch/$(HEADER_ARCH)/um/Kconfig" 92 128 ··· 240 200 increase in the size of the state which needs to be saved when handling 241 201 signals. 242 202 243 - config MMAPPER 244 - tristate "iomem emulation driver" 245 - help 246 - This driver allows a host file to be used as emulated IO memory inside 247 - UML. 248 - 249 203 config PGTABLE_LEVELS 250 204 int 251 205 default 4 if 64BIT ··· 294 260 295 261 config ARCH_SUSPEND_POSSIBLE 296 262 def_bool y 263 + depends on !SMP 297 264 298 265 menu "Power management options" 299 266
+5 -7
arch/um/Makefile
··· 46 46 ARCH_INCLUDE += -I$(srctree)/$(HOST_DIR)/um/shared 47 47 KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um 48 48 49 - # -Dvmap=kernel_vmap prevents anything from referencing the libpcap.o symbol so 50 - # named - it's a common symbol in libpcap, so we get a binary which crashes. 51 - # 52 - # Same things for in6addr_loopback and mktime - found in libc. For these two we 53 - # only get link-time error, luckily. 49 + # -Dstrrchr=kernel_strrchr (as well as the various in6addr symbols) prevents 50 + # anything from referencing 51 + # libc symbols with the same name, which can cause a linker error. 54 52 # 55 53 # -Dlongjmp=kernel_longjmp prevents anything from referencing the libpthread.a 56 54 # embedded copy of longjmp, same thing for setjmp. 57 55 # 58 - # These apply to USER_CFLAGS to. 56 + # These apply to USER_CFLAGS too. 59 57 60 58 KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ 61 - $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ 59 + $(ARCH_INCLUDE) $(MODE_INCLUDE) \ 62 60 -Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \ 63 61 -Din6addr_loopback=kernel_in6addr_loopback \ 64 62 -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr \
-1
arch/um/drivers/Makefile
··· 29 29 30 30 obj-$(CONFIG_UML_NET_VECTOR) += vector.o 31 31 obj-$(CONFIG_MCONSOLE) += mconsole.o 32 - obj-$(CONFIG_MMAPPER) += mmapper_kern.o 33 32 obj-$(CONFIG_BLK_DEV_UBD) += ubd.o 34 33 obj-$(CONFIG_UML_SOUND) += hostaudio.o 35 34 obj-$(CONFIG_NULL_CHAN) += null.o
-135
arch/um/drivers/mmapper_kern.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * arch/um/drivers/mmapper_kern.c 4 - * 5 - * BRIEF MODULE DESCRIPTION 6 - * 7 - * Copyright (C) 2000 RidgeRun, Inc. 8 - * Author: RidgeRun, Inc. 9 - * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com 10 - * 11 - */ 12 - 13 - #include <linux/stddef.h> 14 - #include <linux/types.h> 15 - #include <linux/fs.h> 16 - #include <linux/init.h> 17 - #include <linux/miscdevice.h> 18 - #include <linux/module.h> 19 - #include <linux/mm.h> 20 - 21 - #include <linux/uaccess.h> 22 - #include <mem_user.h> 23 - 24 - /* These are set in mmapper_init, which is called at boot time */ 25 - static unsigned long mmapper_size; 26 - static unsigned long p_buf; 27 - static char *v_buf; 28 - 29 - static ssize_t mmapper_read(struct file *file, char __user *buf, size_t count, 30 - loff_t *ppos) 31 - { 32 - return simple_read_from_buffer(buf, count, ppos, v_buf, mmapper_size); 33 - } 34 - 35 - static ssize_t mmapper_write(struct file *file, const char __user *buf, 36 - size_t count, loff_t *ppos) 37 - { 38 - if (*ppos > mmapper_size) 39 - return -EINVAL; 40 - 41 - return simple_write_to_buffer(v_buf, mmapper_size, ppos, buf, count); 42 - } 43 - 44 - static long mmapper_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 45 - { 46 - return -ENOIOCTLCMD; 47 - } 48 - 49 - static int mmapper_mmap(struct file *file, struct vm_area_struct *vma) 50 - { 51 - int ret = -EINVAL; 52 - int size; 53 - 54 - if (vma->vm_pgoff != 0) 55 - goto out; 56 - 57 - size = vma->vm_end - vma->vm_start; 58 - if (size > mmapper_size) 59 - return -EFAULT; 60 - 61 - /* 62 - * XXX A comment above remap_pfn_range says it should only be 63 - * called when the mm semaphore is held 64 - */ 65 - if (remap_pfn_range(vma, vma->vm_start, p_buf >> PAGE_SHIFT, size, 66 - vma->vm_page_prot)) 67 - goto out; 68 - ret = 0; 69 - out: 70 - return ret; 71 - } 72 - 73 - static int mmapper_open(struct inode *inode, struct file *file) 74 - { 75 - return 0; 76 - } 77 - 78 - static int mmapper_release(struct inode *inode, struct file *file) 79 - { 80 - return 0; 81 - } 82 - 83 - static const struct file_operations mmapper_fops = { 84 - .owner = THIS_MODULE, 85 - .read = mmapper_read, 86 - .write = mmapper_write, 87 - .unlocked_ioctl = mmapper_ioctl, 88 - .mmap = mmapper_mmap, 89 - .open = mmapper_open, 90 - .release = mmapper_release, 91 - .llseek = default_llseek, 92 - }; 93 - 94 - /* 95 - * No locking needed - only used (and modified) by below initcall and exitcall. 96 - */ 97 - static struct miscdevice mmapper_dev = { 98 - .minor = MISC_DYNAMIC_MINOR, 99 - .name = "mmapper", 100 - .fops = &mmapper_fops 101 - }; 102 - 103 - static int __init mmapper_init(void) 104 - { 105 - int err; 106 - 107 - printk(KERN_INFO "Mapper v0.1\n"); 108 - 109 - v_buf = (char *) find_iomem("mmapper", &mmapper_size); 110 - if (mmapper_size == 0) { 111 - printk(KERN_ERR "mmapper_init - find_iomem failed\n"); 112 - return -ENODEV; 113 - } 114 - p_buf = __pa(v_buf); 115 - 116 - err = misc_register(&mmapper_dev); 117 - if (err) { 118 - printk(KERN_ERR "mmapper - misc_register failed, err = %d\n", 119 - err); 120 - return err; 121 - } 122 - return 0; 123 - } 124 - 125 - static void __exit mmapper_exit(void) 126 - { 127 - misc_deregister(&mmapper_dev); 128 - } 129 - 130 - module_init(mmapper_init); 131 - module_exit(mmapper_exit); 132 - 133 - MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>"); 134 - MODULE_DESCRIPTION("DSPLinux simulator mmapper driver"); 135 - MODULE_LICENSE("GPL");
+2 -2
arch/um/drivers/virtio_uml.c
··· 24 24 #include <linux/of.h> 25 25 #include <linux/platform_device.h> 26 26 #include <linux/slab.h> 27 + #include <linux/string_choices.h> 27 28 #include <linux/virtio.h> 28 29 #include <linux/virtio_config.h> 29 30 #include <linux/virtio_ring.h> ··· 1152 1151 return; 1153 1152 1154 1153 vu_dev->no_vq_suspend = no_vq_suspend; 1155 - dev_info(&vdev->dev, "%sabled VQ suspend\n", 1156 - no_vq_suspend ? "dis" : "en"); 1154 + dev_info(&vdev->dev, "%s VQ suspend\n", str_disabled_enabled(no_vq_suspend)); 1157 1155 } 1158 1156 1159 1157 static void vu_of_conn_broken(struct work_struct *wk)
+3 -2
arch/um/include/asm/current.h
··· 7 7 8 8 #ifndef __ASSEMBLER__ 9 9 10 + #include <shared/smp.h> 11 + 10 12 struct task_struct; 11 13 extern struct task_struct *cpu_tasks[NR_CPUS]; 12 14 13 15 static __always_inline struct task_struct *get_current(void) 14 16 { 15 - return cpu_tasks[0]; 17 + return cpu_tasks[uml_curr_cpu()]; 16 18 } 17 - 18 19 19 20 #define current get_current() 20 21
+23 -1
arch/um/include/asm/hardirq.h
··· 2 2 #ifndef __ASM_UM_HARDIRQ_H 3 3 #define __ASM_UM_HARDIRQ_H 4 4 5 - #include <asm-generic/hardirq.h> 5 + #include <linux/cache.h> 6 + #include <linux/threads.h> 6 7 7 8 #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 9 + 10 + typedef struct { 11 + unsigned int __softirq_pending; 12 + #if IS_ENABLED(CONFIG_SMP) 13 + unsigned int irq_resched_count; 14 + unsigned int irq_call_count; 15 + #endif 16 + } ____cacheline_aligned irq_cpustat_t; 17 + 18 + DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); 19 + 20 + #define __ARCH_IRQ_STAT 21 + 22 + #define inc_irq_stat(member) this_cpu_inc(irq_stat.member) 23 + 24 + #include <linux/irq.h> 25 + 26 + static inline void ack_bad_irq(unsigned int irq) 27 + { 28 + pr_crit("unexpected IRQ trap at vector %02x\n", irq); 29 + } 8 30 9 31 #endif /* __ASM_UM_HARDIRQ_H */
+2 -2
arch/um/include/asm/irqflags.h
··· 2 2 #ifndef __UM_IRQFLAGS_H 3 3 #define __UM_IRQFLAGS_H 4 4 5 - extern int signals_enabled; 5 + int um_get_signals(void); 6 6 int um_set_signals(int enable); 7 7 void block_signals(void); 8 8 void unblock_signals(void); ··· 10 10 #define arch_local_save_flags arch_local_save_flags 11 11 static inline unsigned long arch_local_save_flags(void) 12 12 { 13 - return signals_enabled; 13 + return um_get_signals(); 14 14 } 15 15 16 16 #define arch_local_irq_restore arch_local_irq_restore
-4
arch/um/include/asm/kasan.h
··· 24 24 25 25 #ifdef CONFIG_KASAN 26 26 void kasan_init(void); 27 - 28 - #if defined(CONFIG_STATIC_LINK) && defined(CONFIG_KASAN_INLINE) 29 - #error UML does not work in KASAN_INLINE mode with STATIC_LINK enabled! 30 - #endif 31 27 #else 32 28 static inline void kasan_init(void) { } 33 29 #endif /* CONFIG_KASAN */
+10
arch/um/include/asm/mmu.h
··· 7 7 #define __ARCH_UM_MMU_H 8 8 9 9 #include "linux/types.h" 10 + #include <linux/mutex.h> 11 + #include <linux/spinlock.h> 10 12 #include <mm_id.h> 11 13 12 14 typedef struct mm_context { 13 15 struct mm_id id; 16 + struct mutex turnstile; 14 17 15 18 struct list_head list; 16 19 17 20 /* Address range in need of a TLB sync */ 21 + spinlock_t sync_tlb_lock; 18 22 unsigned long sync_tlb_range_from; 19 23 unsigned long sync_tlb_range_to; 20 24 } mm_context_t; 25 + 26 + #define INIT_MM_CONTEXT(mm) \ 27 + .context = { \ 28 + .turnstile = __MUTEX_INITIALIZER(mm.context.turnstile), \ 29 + .sync_tlb_lock = __SPIN_LOCK_INITIALIZER(mm.context.sync_tlb_lock), \ 30 + } 21 31 22 32 #endif
-4
arch/um/include/asm/page.h
··· 96 96 97 97 #endif /* __ASSEMBLER__ */ 98 98 99 - #ifdef CONFIG_X86_32 100 - #define __HAVE_ARCH_GATE_AREA 1 101 - #endif 102 - 103 99 #endif /* __UM_PAGE_H */
+6 -2
arch/um/include/asm/pgtable.h
··· 45 45 * area for the same reason. ;) 46 46 */ 47 47 48 - extern unsigned long end_iomem; 48 + #ifndef COMPILE_OFFSETS 49 + #include <as-layout.h> /* for high_physmem */ 50 + #endif 49 51 50 52 #define VMALLOC_OFFSET (__va_space) 51 - #define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) 53 + #define VMALLOC_START ((high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) 52 54 #define VMALLOC_END (TASK_SIZE-2*PAGE_SIZE) 53 55 #define MODULES_VADDR VMALLOC_START 54 56 #define MODULES_END VMALLOC_END ··· 227 225 static inline void um_tlb_mark_sync(struct mm_struct *mm, unsigned long start, 228 226 unsigned long end) 229 227 { 228 + guard(spinlock_irqsave)(&mm->context.sync_tlb_lock); 229 + 230 230 if (!mm->context.sync_tlb_range_to) { 231 231 mm->context.sync_tlb_range_from = start; 232 232 mm->context.sync_tlb_range_to = end;
+14 -1
arch/um/include/asm/smp.h
··· 2 2 #ifndef __UM_SMP_H 3 3 #define __UM_SMP_H 4 4 5 - #define hard_smp_processor_id() 0 5 + #if IS_ENABLED(CONFIG_SMP) 6 + 7 + #include <linux/cpumask.h> 8 + #include <shared/smp.h> 9 + 10 + #define raw_smp_processor_id() uml_curr_cpu() 11 + 12 + void arch_smp_send_reschedule(int cpu); 13 + 14 + void arch_send_call_function_single_ipi(int cpu); 15 + 16 + void arch_send_call_function_ipi_mask(const struct cpumask *mask); 17 + 18 + #endif /* CONFIG_SMP */ 6 19 7 20 #endif
+1 -8
arch/um/include/asm/uaccess.h
··· 15 15 (((unsigned long) (addr) < TASK_SIZE) && \ 16 16 (((unsigned long) (addr) + (size)) < TASK_SIZE)) 17 17 18 - #define __access_ok_vsyscall(addr, size) \ 19 - (((unsigned long) (addr) >= FIXADDR_USER_START) && \ 20 - ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ 21 - ((unsigned long) (addr) + (size) >= (unsigned long)(addr))) 22 - 23 18 #define __addr_range_nowrap(addr, size) \ 24 19 ((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) 25 20 ··· 35 40 static inline int __access_ok(const void __user *ptr, unsigned long size) 36 41 { 37 42 unsigned long addr = (unsigned long)ptr; 38 - return __addr_range_nowrap(addr, size) && 39 - (__under_task_size(addr, size) || 40 - __access_ok_vsyscall(addr, size)); 43 + return __addr_range_nowrap(addr, size) && __under_task_size(addr, size); 41 44 } 42 45 43 46 #define __get_kernel_nofault(dst, src, type, err_label) \
+17
arch/um/include/linux/smp-internal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __UM_SMP_INTERNAL_H 3 + #define __UM_SMP_INTERNAL_H 4 + 5 + #if IS_ENABLED(CONFIG_SMP) 6 + 7 + void prefill_possible_map(void); 8 + 9 + #else /* !CONFIG_SMP */ 10 + 11 + static inline void prefill_possible_map(void) { } 12 + 13 + #endif /* CONFIG_SMP */ 14 + 15 + extern char cpu_irqstacks[NR_CPUS][THREAD_SIZE] __aligned(THREAD_SIZE); 16 + 17 + #endif /* __UM_SMP_INTERNAL_H */
+3
arch/um/include/linux/time-internal.h
··· 90 90 * which is intentional since we really shouldn't link it in that case. 91 91 */ 92 92 void time_travel_ndelay(unsigned long nsec); 93 + 94 + int um_setup_timer(void); 95 + 93 96 #endif /* __TIMER_INTERNAL_H__ */
-1
arch/um/include/shared/as-layout.h
··· 44 44 45 45 extern unsigned long brk_start; 46 46 47 - extern unsigned long host_task_size; 48 47 extern unsigned long stub_start; 49 48 50 49 extern int linux_main(int argc, char **argv, char **envp);
-20
arch/um/include/shared/common-offsets.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* for use by sys-$SUBARCH/kernel-offsets.c */ 3 - 4 - DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); 5 - 6 - DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); 7 - DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK); 8 - DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT); 9 - 10 - DEFINE(UM_GFP_KERNEL, GFP_KERNEL); 11 - DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC); 12 - 13 - DEFINE(UM_THREAD_SIZE, THREAD_SIZE); 14 - 15 - DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); 16 - DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); 17 - 18 - DEFINE(UM_KERN_GDT_ENTRY_TLS_ENTRIES, GDT_ENTRY_TLS_ENTRIES); 19 - 20 - DEFINE(UM_SECCOMP_ARCH_NATIVE, SECCOMP_ARCH_NATIVE);
+1 -4
arch/um/include/shared/kern_util.h
··· 15 15 16 16 extern int kmalloc_ok; 17 17 18 - #define UML_ROUND_UP(addr) \ 19 - ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK) 20 - 21 18 extern unsigned long alloc_stack(int order, int atomic); 22 19 extern void free_stack(unsigned long stack, int order); 23 20 ··· 39 42 40 43 extern int start_uml(void); 41 44 extern void paging_init(void); 42 - extern int parse_iomem(char *str, int *add); 43 45 44 46 extern void uml_cleanup(void); 45 47 extern void do_uml_exitcalls(void); ··· 51 55 extern int get_current_pid(void); 52 56 extern int copy_from_user_proc(void *to, void *from, int size); 53 57 extern char *uml_strdup(const char *string); 58 + int uml_need_resched(void); 54 59 55 60 extern unsigned long to_irq_stack(unsigned long *mask_out); 56 61 extern unsigned long from_irq_stack(int nested);
+1 -2
arch/um/include/shared/longjmp.h
··· 5 5 #include <sysdep/archsetjmp.h> 6 6 #include <os.h> 7 7 8 - extern int signals_enabled; 9 8 extern int setjmp(jmp_buf); 10 9 extern void longjmp(jmp_buf, int); 11 10 ··· 14 15 15 16 #define UML_SETJMP(buf) ({ \ 16 17 int n, enable; \ 17 - enable = *(volatile int *)&signals_enabled; \ 18 + enable = um_get_signals(); \ 18 19 n = setjmp(*buf); \ 19 20 if(n != 0) \ 20 21 um_set_signals_trace(enable); \
-13
arch/um/include/shared/mem_user.h
··· 32 32 #ifndef _MEM_USER_H 33 33 #define _MEM_USER_H 34 34 35 - struct iomem_region { 36 - struct iomem_region *next; 37 - char *driver; 38 - int fd; 39 - int size; 40 - unsigned long phys; 41 - unsigned long virt; 42 - }; 43 - 44 - extern struct iomem_region *iomem_regions; 45 - extern int iomem_size; 46 - 47 35 #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) 48 36 49 - extern unsigned long find_iomem(char *driver, unsigned long *len_out); 50 37 extern void setup_physmem(unsigned long start, unsigned long usable, 51 38 unsigned long len); 52 39 extern void map_memory(unsigned long virt, unsigned long phys,
+21 -3
arch/um/include/shared/os.h
··· 216 216 217 217 void os_set_pdeathsig(void); 218 218 219 + int os_futex_wait(void *uaddr, unsigned int val); 220 + int os_futex_wake(void *uaddr); 221 + 219 222 /* execvp.c */ 220 223 extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); 221 224 /* helper.c */ ··· 246 243 extern int change_sig(int signal, int on); 247 244 extern void block_signals(void); 248 245 extern void unblock_signals(void); 246 + extern int um_get_signals(void); 249 247 extern int um_set_signals(int enable); 250 248 extern int um_set_signals_trace(int enable); 251 249 extern void deliver_alarm(void); ··· 270 266 __attribute__ ((format (printf, 1, 2))); 271 267 272 268 /* time.c */ 269 + void os_idle_prepare(void); 273 270 extern void os_idle_sleep(void); 274 271 extern int os_timer_create(void); 275 - extern int os_timer_set_interval(unsigned long long nsecs); 276 - extern int os_timer_one_shot(unsigned long long nsecs); 277 - extern void os_timer_disable(void); 272 + extern int os_timer_set_interval(int cpu, unsigned long long nsecs); 273 + extern int os_timer_one_shot(int cpu, unsigned long long nsecs); 274 + extern void os_timer_disable(int cpu); 278 275 extern long long os_persistent_clock_emulation(void); 279 276 extern long long os_nsecs(void); 280 277 ··· 342 337 343 338 /* time-travel */ 344 339 extern void deliver_time_travel_irqs(void); 340 + 341 + /* smp.c */ 342 + #if IS_ENABLED(CONFIG_SMP) 343 + void os_init_smp(void); 344 + int os_start_cpu_thread(int cpu); 345 + void os_start_secondary(void *arg, jmp_buf *switch_buf); 346 + int os_send_ipi(int cpu, int vector); 347 + void os_local_ipi_enable(void); 348 + void os_local_ipi_disable(void); 349 + #else /* !CONFIG_SMP */ 350 + static inline void os_local_ipi_enable(void) { } 351 + static inline void os_local_ipi_disable(void) { } 352 + #endif /* CONFIG_SMP */ 345 353 346 354 #endif
+5
arch/um/include/shared/skas/mm_id.h
··· 6 6 #ifndef __MM_ID_H 7 7 #define __MM_ID_H 8 8 9 + #include <linux/compiler_types.h> 10 + 9 11 #define STUB_MAX_FDS 4 10 12 11 13 struct mm_id { ··· 20 18 int syscall_fd_num; 21 19 int syscall_fd_map[STUB_MAX_FDS]; 22 20 }; 21 + 22 + void enter_turnstile(struct mm_id *mm_id) __acquires(turnstile); 23 + void exit_turnstile(struct mm_id *mm_id) __releases(turnstile); 23 24 24 25 void notify_mm_kill(int pid); 25 26
+2
arch/um/include/shared/skas/skas.h
··· 15 15 extern unsigned long current_stub_stack(void); 16 16 extern struct mm_id *current_mm_id(void); 17 17 extern void current_mm_sync(void); 18 + void initial_jmpbuf_lock(void); 19 + void initial_jmpbuf_unlock(void); 18 20 19 21 #endif
+20
arch/um/include/shared/smp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __UM_SHARED_SMP_H 3 + #define __UM_SHARED_SMP_H 4 + 5 + #if IS_ENABLED(CONFIG_SMP) 6 + 7 + extern int uml_ncpus; 8 + 9 + int uml_curr_cpu(void); 10 + void uml_start_secondary(void *opaque); 11 + void uml_ipi_handler(int vector); 12 + 13 + #else /* !CONFIG_SMP */ 14 + 15 + #define uml_ncpus 1 16 + #define uml_curr_cpu() 0 17 + 18 + #endif /* CONFIG_SMP */ 19 + 20 + #endif /* __UM_SHARED_SMP_H */
+1
arch/um/kernel/Makefile
··· 25 25 obj-$(CONFIG_OF) += dtb.o 26 26 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 27 27 obj-$(CONFIG_STACKTRACE) += stacktrace.o 28 + obj-$(CONFIG_SMP) += smp.o 28 29 29 30 USER_OBJS := config.o 30 31
+43 -1
arch/um/kernel/asm-offsets.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 1 2 #define COMPILE_OFFSETS 3 + #include <linux/stddef.h> 4 + #include <linux/sched.h> 5 + #include <linux/elf.h> 6 + #include <linux/crypto.h> 7 + #include <linux/kbuild.h> 8 + #include <linux/audit.h> 9 + #include <linux/fs.h> 10 + #include <asm/mman.h> 11 + #include <asm/seccomp.h> 2 12 3 - #include <sysdep/kernel-offsets.h> 13 + /* workaround for a warning with -Wmissing-prototypes */ 14 + void foo(void); 15 + 16 + void foo(void) 17 + { 18 + DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); 19 + 20 + DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); 21 + DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK); 22 + DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT); 23 + 24 + DEFINE(UM_GFP_KERNEL, GFP_KERNEL); 25 + DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC); 26 + 27 + DEFINE(UM_THREAD_SIZE, THREAD_SIZE); 28 + 29 + DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); 30 + DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); 31 + 32 + DEFINE(UM_KERN_GDT_ENTRY_TLS_ENTRIES, GDT_ENTRY_TLS_ENTRIES); 33 + 34 + DEFINE(UM_SECCOMP_ARCH_NATIVE, SECCOMP_ARCH_NATIVE); 35 + 36 + DEFINE(HOSTFS_ATTR_MODE, ATTR_MODE); 37 + DEFINE(HOSTFS_ATTR_UID, ATTR_UID); 38 + DEFINE(HOSTFS_ATTR_GID, ATTR_GID); 39 + DEFINE(HOSTFS_ATTR_SIZE, ATTR_SIZE); 40 + DEFINE(HOSTFS_ATTR_ATIME, ATTR_ATIME); 41 + DEFINE(HOSTFS_ATTR_MTIME, ATTR_MTIME); 42 + DEFINE(HOSTFS_ATTR_CTIME, ATTR_CTIME); 43 + DEFINE(HOSTFS_ATTR_ATIME_SET, ATTR_ATIME_SET); 44 + DEFINE(HOSTFS_ATTR_MTIME_SET, ATTR_MTIME_SET); 45 + }
+26 -1
arch/um/kernel/irq.c
··· 22 22 #include <irq_kern.h> 23 23 #include <linux/time-internal.h> 24 24 25 + DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); 26 + 27 + #define irq_stats(x) (&per_cpu(irq_stat, x)) 25 28 26 29 /* When epoll triggers we do not know why it did so 27 30 * we can also have different IRQs for read and write. ··· 686 683 { 687 684 int i; 688 685 689 - irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_edge_irq); 686 + irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_percpu_irq); 690 687 691 688 for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++) 692 689 irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); ··· 703 700 struct uml_pt_regs *regs, void *mc) 704 701 { 705 702 do_IRQ(SIGCHLD_IRQ, regs); 703 + } 704 + 705 + /* 706 + * /proc/interrupts printing for arch specific interrupts 707 + */ 708 + int arch_show_interrupts(struct seq_file *p, int prec) 709 + { 710 + #if IS_ENABLED(CONFIG_SMP) 711 + int cpu; 712 + 713 + seq_printf(p, "%*s: ", prec, "RES"); 714 + for_each_online_cpu(cpu) 715 + seq_printf(p, "%10u ", irq_stats(cpu)->irq_resched_count); 716 + seq_puts(p, " Rescheduling interrupts\n"); 717 + 718 + seq_printf(p, "%*s: ", prec, "CAL"); 719 + for_each_online_cpu(cpu) 720 + seq_printf(p, "%10u ", irq_stats(cpu)->irq_call_count); 721 + seq_puts(p, " Function call interrupts\n"); 722 + #endif 723 + 724 + return 0; 706 725 }
+1 -1
arch/um/kernel/ksyms.c
··· 6 6 #include <linux/module.h> 7 7 #include <os.h> 8 8 9 + EXPORT_SYMBOL(um_get_signals); 9 10 EXPORT_SYMBOL(um_set_signals); 10 - EXPORT_SYMBOL(signals_enabled); 11 11 12 12 EXPORT_SYMBOL(os_stat_fd); 13 13 EXPORT_SYMBOL(os_stat_file);
+2 -109
arch/um/kernel/mem.c
··· 71 71 /* Map in the area just after the brk now that kmalloc is about 72 72 * to be turned on. 73 73 */ 74 - brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); 74 + brk_end = PAGE_ALIGN((unsigned long) sbrk(0)); 75 75 map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); 76 76 memblock_free((void *)brk_end, uml_reserved - brk_end); 77 77 uml_reserved = brk_end; ··· 84 84 kmalloc_ok = 1; 85 85 } 86 86 87 - #if IS_ENABLED(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) 88 - /* 89 - * Create a page table and place a pointer to it in a middle page 90 - * directory entry. 91 - */ 92 - static void __init one_page_table_init(pmd_t *pmd) 93 - { 94 - if (pmd_none(*pmd)) { 95 - pte_t *pte = (pte_t *) memblock_alloc_low(PAGE_SIZE, 96 - PAGE_SIZE); 97 - if (!pte) 98 - panic("%s: Failed to allocate %lu bytes align=%lx\n", 99 - __func__, PAGE_SIZE, PAGE_SIZE); 100 - 101 - set_pmd(pmd, __pmd(_KERNPG_TABLE + 102 - (unsigned long) __pa(pte))); 103 - BUG_ON(pte != pte_offset_kernel(pmd, 0)); 104 - } 105 - } 106 - 107 - static void __init one_md_table_init(pud_t *pud) 108 - { 109 - #if CONFIG_PGTABLE_LEVELS > 2 110 - pmd_t *pmd_table = (pmd_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 111 - if (!pmd_table) 112 - panic("%s: Failed to allocate %lu bytes align=%lx\n", 113 - __func__, PAGE_SIZE, PAGE_SIZE); 114 - 115 - set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table))); 116 - BUG_ON(pmd_table != pmd_offset(pud, 0)); 117 - #endif 118 - } 119 - 120 - static void __init one_ud_table_init(p4d_t *p4d) 121 - { 122 - #if CONFIG_PGTABLE_LEVELS > 3 123 - pud_t *pud_table = (pud_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 124 - if (!pud_table) 125 - panic("%s: Failed to allocate %lu bytes align=%lx\n", 126 - __func__, PAGE_SIZE, PAGE_SIZE); 127 - 128 - set_p4d(p4d, __p4d(_KERNPG_TABLE + (unsigned long) __pa(pud_table))); 129 - BUG_ON(pud_table != pud_offset(p4d, 0)); 130 - #endif 131 - } 132 - 133 - static void __init fixrange_init(unsigned long start, unsigned long end, 134 - pgd_t *pgd_base) 135 - { 136 - pgd_t *pgd; 137 - p4d_t *p4d; 138 - pud_t *pud; 139 - pmd_t *pmd; 140 - int i, j; 141 - unsigned long vaddr; 142 - 143 - vaddr = start; 144 - i = pgd_index(vaddr); 145 - j = pmd_index(vaddr); 146 - pgd = pgd_base + i; 147 - 148 - for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { 149 - p4d = p4d_offset(pgd, vaddr); 150 - if (p4d_none(*p4d)) 151 - one_ud_table_init(p4d); 152 - pud = pud_offset(p4d, vaddr); 153 - if (pud_none(*pud)) 154 - one_md_table_init(pud); 155 - pmd = pmd_offset(pud, vaddr); 156 - for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) { 157 - one_page_table_init(pmd); 158 - vaddr += PMD_SIZE; 159 - } 160 - j = 0; 161 - } 162 - } 163 - 164 - static void __init fixaddr_user_init( void) 165 - { 166 - long size = FIXADDR_USER_END - FIXADDR_USER_START; 167 - pte_t *pte; 168 - phys_t p; 169 - unsigned long v, vaddr = FIXADDR_USER_START; 170 - 171 - if (!size) 172 - return; 173 - 174 - fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir); 175 - v = (unsigned long) memblock_alloc_low(size, PAGE_SIZE); 176 - if (!v) 177 - panic("%s: Failed to allocate %lu bytes align=%lx\n", 178 - __func__, size, PAGE_SIZE); 179 - 180 - memcpy((void *) v , (void *) FIXADDR_USER_START, size); 181 - p = __pa(v); 182 - for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE, 183 - p += PAGE_SIZE) { 184 - pte = virt_to_kpte(vaddr); 185 - pte_set_val(*pte, p, PAGE_READONLY); 186 - } 187 - } 188 - #endif 189 - 190 87 void __init paging_init(void) 191 88 { 192 89 unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; ··· 94 197 panic("%s: Failed to allocate %lu bytes align=%lx\n", 95 198 __func__, PAGE_SIZE, PAGE_SIZE); 96 199 97 - max_zone_pfn[ZONE_NORMAL] = end_iomem >> PAGE_SHIFT; 200 + max_zone_pfn[ZONE_NORMAL] = high_physmem >> PAGE_SHIFT; 98 201 free_area_init(max_zone_pfn); 99 - 100 - #if IS_ENABLED(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) 101 - fixaddr_user_init(); 102 - #endif 103 202 } 104 203 105 204 /*
-71
arch/um/kernel/physmem.c
··· 105 105 fd = physmem_fd; 106 106 *offset_out = phys; 107 107 } 108 - else if (phys < __pa(end_iomem)) { 109 - struct iomem_region *region = iomem_regions; 110 - 111 - while (region != NULL) { 112 - if ((phys >= region->phys) && 113 - (phys < region->phys + region->size)) { 114 - fd = region->fd; 115 - *offset_out = phys - region->phys; 116 - break; 117 - } 118 - region = region->next; 119 - } 120 - } 121 108 122 109 return fd; 123 110 } ··· 127 140 " be more, and the excess, if it's ever used, will just be swapped out.\n" 128 141 " Example: mem=64M\n\n" 129 142 ); 130 - 131 - __uml_setup("iomem=", parse_iomem, 132 - "iomem=<name>,<file>\n" 133 - " Configure <file> as an IO memory region named <name>.\n\n" 134 - ); 135 - 136 - /* 137 - * This list is constructed in parse_iomem and addresses filled in 138 - * setup_iomem, both of which run during early boot. Afterwards, it's 139 - * unchanged. 140 - */ 141 - struct iomem_region *iomem_regions; 142 - 143 - /* Initialized in parse_iomem and unchanged thereafter */ 144 - int iomem_size; 145 - 146 - unsigned long find_iomem(char *driver, unsigned long *len_out) 147 - { 148 - struct iomem_region *region = iomem_regions; 149 - 150 - while (region != NULL) { 151 - if (!strcmp(region->driver, driver)) { 152 - *len_out = region->size; 153 - return region->virt; 154 - } 155 - 156 - region = region->next; 157 - } 158 - 159 - return 0; 160 - } 161 - EXPORT_SYMBOL(find_iomem); 162 - 163 - static int setup_iomem(void) 164 - { 165 - struct iomem_region *region = iomem_regions; 166 - unsigned long iomem_start = high_physmem + PAGE_SIZE; 167 - int err; 168 - 169 - while (region != NULL) { 170 - err = os_map_memory((void *) iomem_start, region->fd, 0, 171 - region->size, 1, 1, 0); 172 - if (err) 173 - printk(KERN_ERR "Mapping iomem region for driver '%s' " 174 - "failed, errno = %d\n", region->driver, -err); 175 - else { 176 - region->virt = iomem_start; 177 - region->phys = __pa(region->virt); 178 - } 179 - 180 - iomem_start += region->size + PAGE_SIZE; 181 - region = region->next; 182 - } 183 - 184 - return 0; 185 - } 186 - 187 - __initcall(setup_iomem);
+13 -5
arch/um/kernel/process.c
··· 43 43 * cares about its entry, so it's OK if another processor is modifying its 44 44 * entry. 45 45 */ 46 - struct task_struct *cpu_tasks[NR_CPUS]; 46 + struct task_struct *cpu_tasks[NR_CPUS] = { 47 + [0 ... NR_CPUS - 1] = &init_task, 48 + }; 47 49 EXPORT_SYMBOL(cpu_tasks); 48 50 49 51 void free_stack(unsigned long stack, int order) ··· 187 185 188 186 void initial_thread_cb(void (*proc)(void *), void *arg) 189 187 { 190 - int save_kmalloc_ok = kmalloc_ok; 191 - 192 - kmalloc_ok = 0; 193 188 initial_thread_cb_skas(proc, arg); 194 - kmalloc_ok = save_kmalloc_ok; 195 189 } 196 190 197 191 int arch_dup_task_struct(struct task_struct *dst, ··· 218 220 um_idle_sleep(); 219 221 } 220 222 223 + void arch_cpu_idle_prepare(void) 224 + { 225 + os_idle_prepare(); 226 + } 227 + 221 228 int __uml_cant_sleep(void) { 222 229 return in_atomic() || irqs_disabled() || in_interrupt(); 223 230 /* Is in_interrupt() really needed? */ 231 + } 232 + 233 + int uml_need_resched(void) 234 + { 235 + return need_resched(); 224 236 } 225 237 226 238 extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
+25 -8
arch/um/kernel/skas/mmu.c
··· 23 23 static spinlock_t mm_list_lock; 24 24 static struct list_head mm_list; 25 25 26 + void enter_turnstile(struct mm_id *mm_id) __acquires(turnstile) 27 + { 28 + struct mm_context *ctx = container_of(mm_id, struct mm_context, id); 29 + 30 + mutex_lock(&ctx->turnstile); 31 + } 32 + 33 + void exit_turnstile(struct mm_id *mm_id) __releases(turnstile) 34 + { 35 + struct mm_context *ctx = container_of(mm_id, struct mm_context, id); 36 + 37 + mutex_unlock(&ctx->turnstile); 38 + } 39 + 26 40 int init_new_context(struct task_struct *task, struct mm_struct *mm) 27 41 { 28 42 struct mm_id *new_id = &mm->context.id; 29 43 unsigned long stack = 0; 30 44 int ret = -ENOMEM; 31 45 46 + mutex_init(&mm->context.turnstile); 47 + spin_lock_init(&mm->context.sync_tlb_lock); 48 + 32 49 stack = __get_free_pages(GFP_KERNEL | __GFP_ZERO, ilog2(STUB_DATA_PAGES)); 33 50 if (stack == 0) 34 51 goto out; 35 52 36 53 new_id->stack = stack; 54 + new_id->syscall_data_len = 0; 55 + new_id->syscall_fd_num = 0; 37 56 38 57 scoped_guard(spinlock_irqsave, &mm_list_lock) { 39 58 /* Insert into list, used for lookups when the child dies */ ··· 92 73 return; 93 74 } 94 75 76 + scoped_guard(spinlock_irqsave, &mm_list_lock) 77 + list_del(&mm->context.list); 78 + 95 79 if (mmu->id.pid > 0) { 96 80 os_kill_ptraced_process(mmu->id.pid, 1); 97 81 mmu->id.pid = -1; ··· 104 82 os_close_file(mmu->id.sock); 105 83 106 84 free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES)); 107 - 108 - guard(spinlock_irqsave)(&mm_list_lock); 109 - 110 - list_del(&mm->context.list); 111 85 } 112 86 113 87 static irqreturn_t mm_sigchld_irq(int irq, void* dev) ··· 128 110 /* Marks the MM as dead */ 129 111 mm_context->id.pid = -1; 130 112 131 - /* 132 - * NOTE: If SMP is implemented, a futex_wake 133 - * needs to be added here. 134 - */ 135 113 stub_data = (void *)mm_context->id.stack; 136 114 stub_data->futex = FUTEX_IN_KERN; 115 + #if IS_ENABLED(CONFIG_SMP) 116 + os_futex_wake(&stub_data->futex); 117 + #endif 137 118 138 119 /* 139 120 * NOTE: Currently executing syscalls by
+16 -3
arch/um/kernel/skas/process.c
··· 7 7 #include <linux/sched/mm.h> 8 8 #include <linux/sched/task_stack.h> 9 9 #include <linux/sched/task.h> 10 + #include <linux/smp-internal.h> 10 11 11 12 #include <asm/tlbflush.h> 12 13 ··· 27 26 return 0; 28 27 } 29 28 30 - static char cpu0_irqstack[THREAD_SIZE] __aligned(THREAD_SIZE); 29 + char cpu_irqstacks[NR_CPUS][THREAD_SIZE] __aligned(THREAD_SIZE); 31 30 32 31 int __init start_uml(void) 33 32 { 34 - stack_protections((unsigned long) &cpu0_irqstack); 35 - set_sigstack(cpu0_irqstack, THREAD_SIZE); 33 + stack_protections((unsigned long) &cpu_irqstacks[0]); 34 + set_sigstack(cpu_irqstacks[0], THREAD_SIZE); 36 35 37 36 init_new_thread_signals(); 38 37 ··· 64 63 return; 65 64 66 65 um_tlb_sync(current->mm); 66 + } 67 + 68 + static DEFINE_SPINLOCK(initial_jmpbuf_spinlock); 69 + 70 + void initial_jmpbuf_lock(void) 71 + { 72 + spin_lock_irq(&initial_jmpbuf_spinlock); 73 + } 74 + 75 + void initial_jmpbuf_unlock(void) 76 + { 77 + spin_unlock_irq(&initial_jmpbuf_spinlock); 67 78 }
+242
arch/um/kernel/smp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2025 Ant Group 4 + * Author: Tiwei Bie <tiwei.btw@antgroup.com> 5 + * 6 + * Based on the previous implementation in TT mode 7 + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 8 + */ 9 + 10 + #include <linux/sched.h> 11 + #include <linux/sched/task.h> 12 + #include <linux/sched/task_stack.h> 13 + #include <linux/module.h> 14 + #include <linux/processor.h> 15 + #include <linux/threads.h> 16 + #include <linux/cpu.h> 17 + #include <linux/hardirq.h> 18 + #include <linux/smp.h> 19 + #include <linux/smp-internal.h> 20 + #include <init.h> 21 + #include <kern.h> 22 + #include <os.h> 23 + #include <smp.h> 24 + 25 + enum { 26 + UML_IPI_RES = 0, 27 + UML_IPI_CALL_SINGLE, 28 + UML_IPI_CALL, 29 + UML_IPI_STOP, 30 + }; 31 + 32 + void arch_smp_send_reschedule(int cpu) 33 + { 34 + os_send_ipi(cpu, UML_IPI_RES); 35 + } 36 + 37 + void arch_send_call_function_single_ipi(int cpu) 38 + { 39 + os_send_ipi(cpu, UML_IPI_CALL_SINGLE); 40 + } 41 + 42 + void arch_send_call_function_ipi_mask(const struct cpumask *mask) 43 + { 44 + int cpu; 45 + 46 + for_each_cpu(cpu, mask) 47 + os_send_ipi(cpu, UML_IPI_CALL); 48 + } 49 + 50 + void smp_send_stop(void) 51 + { 52 + int cpu, me = smp_processor_id(); 53 + 54 + for_each_online_cpu(cpu) { 55 + if (cpu == me) 56 + continue; 57 + os_send_ipi(cpu, UML_IPI_STOP); 58 + } 59 + } 60 + 61 + static void ipi_handler(int vector, struct uml_pt_regs *regs) 62 + { 63 + struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs); 64 + int cpu = raw_smp_processor_id(); 65 + 66 + irq_enter(); 67 + 68 + if (current->mm) 69 + os_alarm_process(current->mm->context.id.pid); 70 + 71 + switch (vector) { 72 + case UML_IPI_RES: 73 + inc_irq_stat(irq_resched_count); 74 + scheduler_ipi(); 75 + break; 76 + 77 + case UML_IPI_CALL_SINGLE: 78 + inc_irq_stat(irq_call_count); 79 + generic_smp_call_function_single_interrupt(); 80 + break; 81 + 82 + case UML_IPI_CALL: 83 + inc_irq_stat(irq_call_count); 84 + generic_smp_call_function_interrupt(); 85 + break; 86 + 87 + case UML_IPI_STOP: 88 + set_cpu_online(cpu, false); 89 + while (1) 90 + pause(); 91 + break; 92 + 93 + default: 94 + pr_err("CPU#%d received unknown IPI (vector=%d)!\n", cpu, vector); 95 + break; 96 + } 97 + 98 + irq_exit(); 99 + set_irq_regs(old_regs); 100 + } 101 + 102 + void uml_ipi_handler(int vector) 103 + { 104 + struct uml_pt_regs r = { .is_user = 0 }; 105 + 106 + preempt_disable(); 107 + ipi_handler(vector, &r); 108 + preempt_enable(); 109 + } 110 + 111 + /* AP states used only during CPU startup */ 112 + enum { 113 + UML_CPU_PAUSED = 0, 114 + UML_CPU_RUNNING, 115 + }; 116 + 117 + static int cpu_states[NR_CPUS]; 118 + 119 + static int start_secondary(void *unused) 120 + { 121 + int err, cpu = raw_smp_processor_id(); 122 + 123 + notify_cpu_starting(cpu); 124 + set_cpu_online(cpu, true); 125 + 126 + err = um_setup_timer(); 127 + if (err) 128 + panic("CPU#%d failed to setup timer, err = %d", cpu, err); 129 + 130 + local_irq_enable(); 131 + 132 + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 133 + 134 + return 0; 135 + } 136 + 137 + void uml_start_secondary(void *opaque) 138 + { 139 + int cpu = raw_smp_processor_id(); 140 + struct mm_struct *mm = &init_mm; 141 + struct task_struct *idle; 142 + 143 + stack_protections((unsigned long) &cpu_irqstacks[cpu]); 144 + set_sigstack(&cpu_irqstacks[cpu], THREAD_SIZE); 145 + 146 + set_cpu_present(cpu, true); 147 + os_futex_wait(&cpu_states[cpu], UML_CPU_PAUSED); 148 + 149 + smp_rmb(); /* paired with smp_wmb() in __cpu_up() */ 150 + 151 + idle = cpu_tasks[cpu]; 152 + idle->thread_info.cpu = cpu; 153 + 154 + mmgrab(mm); 155 + idle->active_mm = mm; 156 + 157 + idle->thread.request.thread.proc = start_secondary; 158 + idle->thread.request.thread.arg = NULL; 159 + 160 + new_thread(task_stack_page(idle), &idle->thread.switch_buf, 161 + new_thread_handler); 162 + os_start_secondary(opaque, &idle->thread.switch_buf); 163 + } 164 + 165 + void __init smp_prepare_cpus(unsigned int max_cpus) 166 + { 167 + int err, cpu, me = smp_processor_id(); 168 + unsigned long deadline; 169 + 170 + os_init_smp(); 171 + 172 + for_each_possible_cpu(cpu) { 173 + if (cpu == me) 174 + continue; 175 + 176 + pr_debug("Booting processor %d...\n", cpu); 177 + err = os_start_cpu_thread(cpu); 178 + if (err) { 179 + pr_crit("CPU#%d failed to start cpu thread, err = %d", 180 + cpu, err); 181 + continue; 182 + } 183 + 184 + deadline = jiffies + msecs_to_jiffies(1000); 185 + spin_until_cond(cpu_present(cpu) || 186 + time_is_before_jiffies(deadline)); 187 + 188 + if (!cpu_present(cpu)) 189 + pr_crit("CPU#%d failed to boot\n", cpu); 190 + } 191 + } 192 + 193 + int __cpu_up(unsigned int cpu, struct task_struct *tidle) 194 + { 195 + cpu_tasks[cpu] = tidle; 196 + smp_wmb(); /* paired with smp_rmb() in uml_start_secondary() */ 197 + cpu_states[cpu] = UML_CPU_RUNNING; 198 + os_futex_wake(&cpu_states[cpu]); 199 + spin_until_cond(cpu_online(cpu)); 200 + 201 + return 0; 202 + } 203 + 204 + void __init smp_cpus_done(unsigned int max_cpus) 205 + { 206 + } 207 + 208 + /* Set in uml_ncpus_setup */ 209 + int uml_ncpus = 1; 210 + 211 + void __init prefill_possible_map(void) 212 + { 213 + int cpu; 214 + 215 + for (cpu = 0; cpu < uml_ncpus; cpu++) 216 + set_cpu_possible(cpu, true); 217 + for (; cpu < NR_CPUS; cpu++) 218 + set_cpu_possible(cpu, false); 219 + } 220 + 221 + static int __init uml_ncpus_setup(char *line, int *add) 222 + { 223 + *add = 0; 224 + 225 + if (kstrtoint(line, 10, &uml_ncpus)) { 226 + os_warn("%s: Couldn't parse '%s'\n", __func__, line); 227 + return -1; 228 + } 229 + 230 + uml_ncpus = clamp(uml_ncpus, 1, NR_CPUS); 231 + 232 + return 0; 233 + } 234 + 235 + __uml_setup("ncpus=", uml_ncpus_setup, 236 + "ncpus=<# of desired CPUs>\n" 237 + " This tells UML how many virtual processors to start. The maximum\n" 238 + " number of supported virtual processors can be obtained by querying\n" 239 + " the CONFIG_NR_CPUS option using --showconfig.\n\n" 240 + ); 241 + 242 + EXPORT_SYMBOL(uml_curr_cpu);
+41 -17
arch/um/kernel/time.c
··· 625 625 * controller application. 626 626 */ 627 627 unsigned long long next = S64_MAX; 628 + int cpu = raw_smp_processor_id(); 628 629 629 630 if (time_travel_mode == TT_MODE_BASIC) 630 - os_timer_disable(); 631 + os_timer_disable(cpu); 631 632 632 633 time_travel_update_time(next, true); 633 634 ··· 639 638 * This is somewhat wrong - we should get the first 640 639 * one sooner like the os_timer_one_shot() below... 641 640 */ 642 - os_timer_set_interval(time_travel_timer_interval); 641 + os_timer_set_interval(cpu, time_travel_timer_interval); 643 642 } else { 644 - os_timer_one_shot(time_travel_timer_event.time - next); 643 + os_timer_one_shot(cpu, time_travel_timer_event.time - next); 645 644 } 646 645 } 647 646 } ··· 759 758 #define time_travel_del_event(e) do { } while (0) 760 759 #endif 761 760 761 + static struct clock_event_device timer_clockevent[NR_CPUS]; 762 + 762 763 void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 763 764 { 764 765 unsigned long flags; ··· 783 780 784 781 static int itimer_shutdown(struct clock_event_device *evt) 785 782 { 783 + int cpu = evt - &timer_clockevent[0]; 784 + 786 785 if (time_travel_mode != TT_MODE_OFF) 787 786 time_travel_del_event(&time_travel_timer_event); 788 787 789 788 if (time_travel_mode != TT_MODE_INFCPU && 790 789 time_travel_mode != TT_MODE_EXTERNAL) 791 - os_timer_disable(); 790 + os_timer_disable(cpu); 792 791 793 792 return 0; 794 793 } ··· 798 793 static int itimer_set_periodic(struct clock_event_device *evt) 799 794 { 800 795 unsigned long long interval = NSEC_PER_SEC / HZ; 796 + int cpu = evt - &timer_clockevent[0]; 801 797 802 798 if (time_travel_mode != TT_MODE_OFF) { 803 799 time_travel_del_event(&time_travel_timer_event); ··· 811 805 812 806 if (time_travel_mode != TT_MODE_INFCPU && 813 807 time_travel_mode != TT_MODE_EXTERNAL) 814 - os_timer_set_interval(interval); 808 + os_timer_set_interval(cpu, interval); 815 809 816 810 return 0; 817 811 } ··· 831 825 832 826 if (time_travel_mode != TT_MODE_INFCPU && 833 827 time_travel_mode != TT_MODE_EXTERNAL) 834 - return os_timer_one_shot(delta); 828 + return os_timer_one_shot(raw_smp_processor_id(), delta); 835 829 836 830 return 0; 837 831 } ··· 841 835 return itimer_next_event(0, evt); 842 836 } 843 837 844 - static struct clock_event_device timer_clockevent = { 838 + static struct clock_event_device _timer_clockevent = { 845 839 .name = "posix-timer", 846 840 .rating = 250, 847 - .cpumask = cpu_possible_mask, 848 841 .features = CLOCK_EVT_FEAT_PERIODIC | 849 842 CLOCK_EVT_FEAT_ONESHOT, 850 843 .set_state_shutdown = itimer_shutdown, ··· 861 856 862 857 static irqreturn_t um_timer(int irq, void *dev) 863 858 { 859 + int cpu = raw_smp_processor_id(); 860 + struct clock_event_device *evt = &timer_clockevent[cpu]; 861 + 864 862 /* 865 863 * Interrupt the (possibly) running userspace process, technically this 866 864 * should only happen if userspace is currently executing. ··· 875 867 get_current()->mm) 876 868 os_alarm_process(get_current()->mm->context.id.pid); 877 869 878 - (*timer_clockevent.event_handler)(&timer_clockevent); 870 + evt->event_handler(evt); 879 871 880 872 return IRQ_HANDLED; 881 873 } ··· 912 904 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 913 905 }; 914 906 915 - static void __init um_timer_setup(void) 907 + int um_setup_timer(void) 908 + { 909 + int cpu = raw_smp_processor_id(); 910 + struct clock_event_device *evt = &timer_clockevent[cpu]; 911 + int err; 912 + 913 + err = os_timer_create(); 914 + if (err) 915 + return err; 916 + 917 + memcpy(evt, &_timer_clockevent, sizeof(*evt)); 918 + evt->cpumask = cpumask_of(cpu); 919 + clockevents_register_device(evt); 920 + 921 + return 0; 922 + } 923 + 924 + static void __init um_timer_init(void) 916 925 { 917 926 int err; 918 927 ··· 938 913 printk(KERN_ERR "register_timer : request_irq failed - " 939 914 "errno = %d\n", -err); 940 915 941 - err = os_timer_create(); 942 - if (err != 0) { 916 + err = um_setup_timer(); 917 + if (err) { 943 918 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); 944 919 return; 945 920 } ··· 949 924 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 950 925 return; 951 926 } 952 - clockevents_register_device(&timer_clockevent); 953 927 } 954 928 955 929 void read_persistent_clock64(struct timespec64 *ts) ··· 969 945 void __init time_init(void) 970 946 { 971 947 timer_set_signal_handler(); 972 - late_time_init = um_timer_setup; 948 + late_time_init = um_timer_init; 973 949 } 974 950 975 951 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT ··· 985 961 { 986 962 if (strcmp(str, "=inf-cpu") == 0) { 987 963 time_travel_mode = TT_MODE_INFCPU; 988 - timer_clockevent.name = "time-travel-timer-infcpu"; 964 + _timer_clockevent.name = "time-travel-timer-infcpu"; 989 965 timer_clocksource.name = "time-travel-clock"; 990 966 return 1; 991 967 } 992 968 993 969 if (strncmp(str, "=ext:", 5) == 0) { 994 970 time_travel_mode = TT_MODE_EXTERNAL; 995 - timer_clockevent.name = "time-travel-timer-external"; 971 + _timer_clockevent.name = "time-travel-timer-external"; 996 972 timer_clocksource.name = "time-travel-clock-external"; 997 973 return time_travel_connect_external(str + 5); 998 974 } 999 975 1000 976 if (!*str) { 1001 977 time_travel_mode = TT_MODE_BASIC; 1002 - timer_clockevent.name = "time-travel-timer"; 978 + _timer_clockevent.name = "time-travel-timer"; 1003 979 timer_clocksource.name = "time-travel-clock"; 1004 980 return 1; 1005 981 }
+4 -1
arch/um/kernel/tlb.c
··· 162 162 { 163 163 pgd_t *pgd; 164 164 struct vm_ops ops; 165 - unsigned long addr = mm->context.sync_tlb_range_from, next; 165 + unsigned long addr, next; 166 166 int ret = 0; 167 + 168 + guard(spinlock_irqsave)(&mm->context.sync_tlb_lock); 167 169 168 170 if (mm->context.sync_tlb_range_to == 0) 169 171 return 0; ··· 179 177 ops.unmap = unmap; 180 178 } 181 179 180 + addr = mm->context.sync_tlb_range_from; 182 181 pgd = pgd_offset(mm, addr); 183 182 do { 184 183 next = pgd_addr_end(addr, mm->context.sync_tlb_range_to);
+1 -1
arch/um/kernel/trap.c
··· 316 316 if (!is_user && regs) 317 317 current->thread.segv_regs = container_of(regs, struct pt_regs, regs); 318 318 319 - if (!is_user && init_mm.context.sync_tlb_range_to) { 319 + if (!is_user && address >= start_vm && address < end_vm) { 320 320 /* 321 321 * Kernel has pending updates from set_ptes that were not 322 322 * flushed yet. Syncing them should fix the pagefault (if not
+29 -20
arch/um/kernel/um_arch.c
··· 19 19 #include <linux/kmsg_dump.h> 20 20 #include <linux/suspend.h> 21 21 #include <linux/random.h> 22 + #include <linux/smp-internal.h> 22 23 23 24 #include <asm/processor.h> 24 25 #include <asm/cpufeature.h> ··· 72 71 { 73 72 int i = 0; 74 73 74 + #if IS_ENABLED(CONFIG_SMP) 75 + i = (uintptr_t) v - 1; 76 + if (!cpu_online(i)) 77 + return 0; 78 + #endif 79 + 75 80 seq_printf(m, "processor\t: %d\n", i); 76 81 seq_printf(m, "vendor_id\t: User Mode Linux\n"); 77 82 seq_printf(m, "model name\t: UML\n"); ··· 94 87 loops_per_jiffy/(500000/HZ), 95 88 (loops_per_jiffy/(5000/HZ)) % 100); 96 89 97 - 98 90 return 0; 99 91 } 100 92 101 93 static void *c_start(struct seq_file *m, loff_t *pos) 102 94 { 103 - return *pos < nr_cpu_ids ? &boot_cpu_data + *pos : NULL; 95 + if (*pos < nr_cpu_ids) 96 + return (void *)(uintptr_t)(*pos + 1); 97 + return NULL; 104 98 } 105 99 106 100 static void *c_next(struct seq_file *m, void *v, loff_t *pos) ··· 247 239 248 240 void uml_finishsetup(void) 249 241 { 250 - cpu_tasks[0] = &init_task; 251 - 252 242 atomic_notifier_chain_register(&panic_notifier_list, 253 243 &panic_exit_notifier); 254 244 ··· 260 254 unsigned long task_size; 261 255 EXPORT_SYMBOL(task_size); 262 256 263 - unsigned long host_task_size; 264 - 265 257 unsigned long brk_start; 266 - unsigned long end_iomem; 267 - EXPORT_SYMBOL(end_iomem); 268 258 269 259 #define MIN_VMALLOC (32 * 1024 * 1024) 270 260 ··· 300 298 top_addr = (unsigned long) envp[i]; 301 299 } 302 300 303 - top_addr &= ~(UM_KERN_PAGE_SIZE - 1); 304 - top_addr += UM_KERN_PAGE_SIZE; 305 - 306 - return top_addr; 301 + return PAGE_ALIGN(top_addr + 1); 307 302 } 308 303 309 304 int __init linux_main(int argc, char **argv, char **envp) 310 305 { 311 306 unsigned long avail, diff; 312 307 unsigned long virtmem_size, max_physmem; 308 + unsigned long host_task_size; 313 309 unsigned long stack; 314 310 unsigned int i; 315 311 int add; ··· 354 354 * so they actually get what they asked for. This should 355 355 * add zero for non-exec shield users 356 356 */ 357 - 358 - diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 357 + diff = PAGE_ALIGN(brk_start) - PAGE_ALIGN((unsigned long) &_end); 359 358 if (diff > 1024 * 1024) { 360 359 os_info("Adding %ld bytes to physical memory to account for " 361 360 "exec-shield gap\n", diff); 362 - physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 361 + physmem_size += diff; 363 362 } 364 363 365 364 uml_physmem = (unsigned long) __binary_start & PAGE_MASK; ··· 368 369 369 370 setup_machinename(init_utsname()->machine); 370 371 371 - physmem_size = (physmem_size + PAGE_SIZE - 1) & PAGE_MASK; 372 - iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; 373 - 374 - max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; 372 + physmem_size = PAGE_ALIGN(physmem_size); 373 + max_physmem = TASK_SIZE - uml_physmem - MIN_VMALLOC; 375 374 if (physmem_size > max_physmem) { 376 375 physmem_size = max_physmem; 377 376 os_info("Physical memory size shrunk to %llu bytes\n", ··· 377 380 } 378 381 379 382 high_physmem = uml_physmem + physmem_size; 380 - end_iomem = high_physmem + iomem_size; 381 383 382 384 start_vm = VMALLOC_START; 383 385 ··· 417 421 strscpy(boot_command_line, command_line, COMMAND_LINE_SIZE); 418 422 *cmdline_p = command_line; 419 423 setup_hostinfo(host_info, sizeof host_info); 424 + prefill_possible_map(); 420 425 421 426 if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) { 422 427 add_bootloader_randomness(rng_seed, sizeof(rng_seed)); ··· 451 454 void apply_alternatives(struct alt_instr *start, struct alt_instr *end) 452 455 { 453 456 } 457 + 458 + #if IS_ENABLED(CONFIG_SMP) 459 + void alternatives_smp_module_add(struct module *mod, char *name, 460 + void *locks, void *locks_end, 461 + void *text, void *text_end) 462 + { 463 + } 464 + 465 + void alternatives_smp_module_del(struct module *mod) 466 + { 467 + } 468 + #endif 454 469 455 470 void *text_poke(void *addr, const void *opcode, size_t len) 456 471 {
+3 -3
arch/um/os-Linux/Makefile
··· 6 6 # Don't instrument UML-specific code 7 7 KCOV_INSTRUMENT := n 8 8 9 - obj-y = execvp.o file.o helper.o irq.o main.o mem.o process.o \ 9 + obj-y = elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ 10 10 registers.o sigio.o signal.o start_up.o time.o tty.o \ 11 11 umid.o user_syms.o util.o skas/ 12 12 ··· 14 14 15 15 CFLAGS_main.o += -Wno-frame-larger-than 16 16 17 - obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o 17 + obj-$(CONFIG_SMP) += smp.o 18 18 19 19 USER_OBJS := $(user-objs-y) elf_aux.o execvp.o file.o helper.o irq.o \ 20 20 main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ 21 - tty.o umid.o util.o 21 + tty.o umid.o util.o smp.o 22 22 23 23 include $(srctree)/arch/um/scripts/Makefile.rules
+6 -31
arch/um/os-Linux/elf_aux.c
··· 14 14 #include <elf_user.h> 15 15 #include <mem_user.h> 16 16 #include "internal.h" 17 + #include <linux/swab.h> 17 18 19 + #if __BITS_PER_LONG == 64 20 + typedef Elf64_auxv_t elf_auxv_t; 21 + #else 18 22 typedef Elf32_auxv_t elf_auxv_t; 23 + #endif 19 24 20 25 /* These are initialized very early in boot and never changed */ 21 26 char * elf_aux_platform; 22 - extern long elf_aux_hwcap; 23 - unsigned long vsyscall_ehdr; 24 - unsigned long vsyscall_end; 25 - unsigned long __kernel_vsyscall; 27 + long elf_aux_hwcap; 26 28 27 29 __init void scan_elf_aux( char **envp) 28 30 { 29 - long page_size = 0; 30 31 elf_auxv_t * auxv; 31 32 32 33 while ( *envp++ != NULL) ; 33 34 34 35 for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) { 35 36 switch ( auxv->a_type ) { 36 - case AT_SYSINFO: 37 - __kernel_vsyscall = auxv->a_un.a_val; 38 - /* See if the page is under TASK_SIZE */ 39 - if (__kernel_vsyscall < (unsigned long) envp) 40 - __kernel_vsyscall = 0; 41 - break; 42 - case AT_SYSINFO_EHDR: 43 - vsyscall_ehdr = auxv->a_un.a_val; 44 - /* See if the page is under TASK_SIZE */ 45 - if (vsyscall_ehdr < (unsigned long) envp) 46 - vsyscall_ehdr = 0; 47 - break; 48 37 case AT_HWCAP: 49 38 elf_aux_hwcap = auxv->a_un.a_val; 50 39 break; ··· 45 56 elf_aux_platform = 46 57 (char *) (long) auxv->a_un.a_val; 47 58 break; 48 - case AT_PAGESZ: 49 - page_size = auxv->a_un.a_val; 50 - break; 51 59 } 52 - } 53 - if ( ! __kernel_vsyscall || ! vsyscall_ehdr || 54 - ! elf_aux_hwcap || ! elf_aux_platform || 55 - ! page_size || (vsyscall_ehdr % page_size) ) { 56 - __kernel_vsyscall = 0; 57 - vsyscall_ehdr = 0; 58 - elf_aux_hwcap = 0; 59 - elf_aux_platform = "i586"; 60 - } 61 - else { 62 - vsyscall_end = vsyscall_ehdr + page_size; 63 60 } 64 61 }
+13
arch/um/os-Linux/internal.h
··· 4 4 5 5 #include <mm_id.h> 6 6 #include <stub-data.h> 7 + #include <signal.h> 7 8 8 9 /* 9 10 * elf_aux.c ··· 17 16 void check_tmpexec(void); 18 17 19 18 /* 19 + * signal.c 20 + */ 21 + extern __thread int signals_enabled; 22 + int timer_alarm_pending(void); 23 + 24 + /* 20 25 * skas/process.c 21 26 */ 22 27 void wait_stub_done(int pid); 23 28 void wait_stub_done_seccomp(struct mm_id *mm_idp, int running, int wait_sigsys); 29 + 30 + /* 31 + * smp.c 32 + */ 33 + #define IPI_SIGNAL SIGRTMIN 34 + 24 35 #endif /* __UM_OS_LINUX_INTERNAL_H */
+1 -5
arch/um/os-Linux/main.c
··· 21 21 22 22 #define STACKSIZE (8 * 1024 * 1024) 23 23 24 - long elf_aux_hwcap; 25 - 26 24 static void __init set_stklim(void) 27 25 { 28 26 struct rlimit lim; ··· 147 149 install_fatal_handler(SIGINT); 148 150 install_fatal_handler(SIGTERM); 149 151 150 - #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA 151 152 scan_elf_aux(envp); 152 - #endif 153 153 154 154 change_sig(SIGPIPE, 0); 155 155 ret = linux_main(argc, argv, envp); ··· 167 171 */ 168 172 169 173 /* stop timers and set timer signal to be ignored */ 170 - os_timer_disable(); 174 + os_timer_disable(0); 171 175 172 176 /* disable SIGIO for the fds and set SIGIO to be ignored */ 173 177 err = deactivate_all_fds();
+20
arch/um/os-Linux/process.c
··· 10 10 #include <errno.h> 11 11 #include <signal.h> 12 12 #include <fcntl.h> 13 + #include <limits.h> 14 + #include <linux/futex.h> 13 15 #include <sys/mman.h> 14 16 #include <sys/ptrace.h> 15 17 #include <sys/prctl.h> ··· 190 188 void os_set_pdeathsig(void) 191 189 { 192 190 prctl(PR_SET_PDEATHSIG, SIGKILL); 191 + } 192 + 193 + int os_futex_wait(void *uaddr, unsigned int val) 194 + { 195 + int r; 196 + 197 + CATCH_EINTR(r = syscall(__NR_futex, uaddr, FUTEX_WAIT, val, 198 + NULL, NULL, 0)); 199 + return r < 0 ? -errno : r; 200 + } 201 + 202 + int os_futex_wake(void *uaddr) 203 + { 204 + int r; 205 + 206 + CATCH_EINTR(r = syscall(__NR_futex, uaddr, FUTEX_WAKE, INT_MAX, 207 + NULL, NULL, 0)); 208 + return r < 0 ? -errno : r; 193 209 }
+39 -7
arch/um/os-Linux/signal.c
··· 20 20 #include <um_malloc.h> 21 21 #include <sys/ucontext.h> 22 22 #include <timetravel.h> 23 + #include "internal.h" 23 24 24 25 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *mc) = { 25 26 [SIGTRAP] = relay_signal, ··· 69 68 #define SIGCHLD_BIT 2 70 69 #define SIGCHLD_MASK (1 << SIGCHLD_BIT) 71 70 72 - int signals_enabled; 71 + __thread int signals_enabled; 73 72 #if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) 74 73 static int signals_blocked, signals_blocked_pending; 75 74 #endif 76 - static unsigned int signals_pending; 77 - static unsigned int signals_active = 0; 75 + static __thread unsigned int signals_pending; 76 + static __thread unsigned int signals_active; 78 77 79 78 static void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) 80 79 { ··· 158 157 void timer_set_signal_handler(void) 159 158 { 160 159 set_handler(SIGALRM); 160 + } 161 + 162 + int timer_alarm_pending(void) 163 + { 164 + return !!(signals_pending & SIGALRM_MASK); 161 165 } 162 166 163 167 void set_sigstack(void *sig_stack, int size) ··· 259 253 return 0; 260 254 } 261 255 256 + static inline void __block_signals(void) 257 + { 258 + if (!signals_enabled) 259 + return; 260 + 261 + os_local_ipi_disable(); 262 + barrier(); 263 + signals_enabled = 0; 264 + } 265 + 266 + static inline void __unblock_signals(void) 267 + { 268 + if (signals_enabled) 269 + return; 270 + 271 + signals_enabled = 1; 272 + barrier(); 273 + os_local_ipi_enable(); 274 + } 275 + 262 276 void block_signals(void) 263 277 { 264 - signals_enabled = 0; 278 + __block_signals(); 265 279 /* 266 280 * This must return with signals disabled, so this barrier 267 281 * ensures that writes are flushed out before the return. ··· 298 272 if (signals_enabled == 1) 299 273 return; 300 274 301 - signals_enabled = 1; 275 + __unblock_signals(); 276 + 302 277 #if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) 303 278 deliver_time_travel_irqs(); 304 279 #endif ··· 333 306 * tracing that happens inside the handlers we call for the 334 307 * pending signals will mess up the tracing state. 335 308 */ 336 - signals_enabled = 0; 309 + __block_signals(); 337 310 um_trace_signals_off(); 338 311 339 312 /* ··· 365 338 366 339 /* Re-enable signals and trace that we're doing so. */ 367 340 um_trace_signals_on(); 368 - signals_enabled = 1; 341 + __unblock_signals(); 369 342 } 343 + } 344 + 345 + int um_get_signals(void) 346 + { 347 + return signals_enabled; 370 348 } 371 349 372 350 int um_set_signals(int enable)
+25 -21
arch/um/os-Linux/skas/process.c
··· 298 298 .seccomp = using_seccomp, 299 299 .stub_start = STUB_START, 300 300 }; 301 - struct iomem_region *iomem; 302 301 int ret; 303 302 304 303 if (using_seccomp) { ··· 330 331 syscall(__NR_close_range, 0, ~0U, CLOSE_RANGE_CLOEXEC); 331 332 332 333 fcntl(init_data.stub_data_fd, F_SETFD, 0); 333 - 334 - /* In SECCOMP mode, these FDs are passed when needed */ 335 - if (!using_seccomp) { 336 - for (iomem = iomem_regions; iomem; iomem = iomem->next) 337 - fcntl(iomem->fd, F_SETFD, 0); 338 - } 339 334 340 335 /* dup2 signaling FD/socket to STDIN */ 341 336 if (dup2(tramp_data->sockpair[0], 0) < 0) ··· 546 553 void userspace(struct uml_pt_regs *regs) 547 554 { 548 555 int err, status, op; 549 - siginfo_t si_ptrace; 556 + siginfo_t si_local; 550 557 siginfo_t *si; 551 558 int sig; 552 559 ··· 555 562 556 563 while (1) { 557 564 struct mm_id *mm_id = current_mm_id(); 565 + 566 + /* 567 + * At any given time, only one CPU thread can enter the 568 + * turnstile to operate on the same stub process, including 569 + * executing stub system calls (mmap and munmap). 570 + */ 571 + enter_turnstile(mm_id); 558 572 559 573 /* 560 574 * When we are in time-travel mode, userspace can theoretically ··· 630 630 } 631 631 632 632 if (proc_data->si_offset > sizeof(proc_data->sigstack) - sizeof(*si)) 633 - panic("%s - Invalid siginfo offset from child", 634 - __func__); 635 - si = (void *)&proc_data->sigstack[proc_data->si_offset]; 633 + panic("%s - Invalid siginfo offset from child", __func__); 634 + 635 + si = &si_local; 636 + memcpy(si, &proc_data->sigstack[proc_data->si_offset], sizeof(*si)); 636 637 637 638 regs->is_user = 1; 638 639 ··· 729 728 case SIGFPE: 730 729 case SIGWINCH: 731 730 ptrace(PTRACE_GETSIGINFO, pid, 0, 732 - (struct siginfo *)&si_ptrace); 733 - si = &si_ptrace; 731 + (struct siginfo *)&si_local); 732 + si = &si_local; 734 733 break; 735 734 default: 736 735 si = NULL; ··· 740 739 sig = 0; 741 740 } 742 741 } 742 + 743 + exit_turnstile(mm_id); 743 744 744 745 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ 745 746 ··· 812 809 813 810 static jmp_buf initial_jmpbuf; 814 811 815 - /* XXX Make these percpu */ 816 - static void (*cb_proc)(void *arg); 817 - static void *cb_arg; 818 - static jmp_buf *cb_back; 812 + static __thread void (*cb_proc)(void *arg); 813 + static __thread void *cb_arg; 814 + static __thread jmp_buf *cb_back; 819 815 820 816 int start_idle_thread(void *stack, jmp_buf *switch_buf) 821 817 { ··· 868 866 cb_arg = arg; 869 867 cb_back = &here; 870 868 871 - block_signals_trace(); 869 + initial_jmpbuf_lock(); 872 870 if (UML_SETJMP(&here) == 0) 873 871 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); 874 - unblock_signals_trace(); 872 + initial_jmpbuf_unlock(); 875 873 876 874 cb_proc = NULL; 877 875 cb_arg = NULL; ··· 880 878 881 879 void halt_skas(void) 882 880 { 883 - block_signals_trace(); 881 + initial_jmpbuf_lock(); 884 882 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT); 883 + /* unreachable */ 885 884 } 886 885 887 886 static bool noreboot; ··· 902 899 903 900 void reboot_skas(void) 904 901 { 905 - block_signals_trace(); 902 + initial_jmpbuf_lock(); 906 903 UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT); 904 + /* unreachable */ 907 905 }
+148
arch/um/os-Linux/smp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2025 Ant Group 4 + * Author: Tiwei Bie <tiwei.btw@antgroup.com> 5 + */ 6 + 7 + #include <errno.h> 8 + #include <pthread.h> 9 + #include <signal.h> 10 + #include <kern_util.h> 11 + #include <um_malloc.h> 12 + #include <init.h> 13 + #include <os.h> 14 + #include <smp.h> 15 + #include "internal.h" 16 + 17 + struct cpu_thread_data { 18 + int cpu; 19 + sigset_t sigset; 20 + }; 21 + 22 + static __thread int __curr_cpu; 23 + 24 + int uml_curr_cpu(void) 25 + { 26 + return __curr_cpu; 27 + } 28 + 29 + static pthread_t cpu_threads[CONFIG_NR_CPUS]; 30 + 31 + static void *cpu_thread(void *arg) 32 + { 33 + struct cpu_thread_data *data = arg; 34 + 35 + __curr_cpu = data->cpu; 36 + 37 + uml_start_secondary(data); 38 + 39 + return NULL; 40 + } 41 + 42 + int os_start_cpu_thread(int cpu) 43 + { 44 + struct cpu_thread_data *data; 45 + sigset_t sigset, oset; 46 + int err; 47 + 48 + data = uml_kmalloc(sizeof(*data), UM_GFP_ATOMIC); 49 + if (!data) 50 + return -ENOMEM; 51 + 52 + sigfillset(&sigset); 53 + if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) { 54 + err = errno; 55 + goto err; 56 + } 57 + 58 + data->cpu = cpu; 59 + data->sigset = oset; 60 + 61 + err = pthread_create(&cpu_threads[cpu], NULL, cpu_thread, data); 62 + if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 63 + panic("Failed to restore the signal mask, errno = %d", errno); 64 + if (err != 0) 65 + goto err; 66 + 67 + return 0; 68 + 69 + err: 70 + kfree(data); 71 + return -err; 72 + } 73 + 74 + void os_start_secondary(void *arg, jmp_buf *switch_buf) 75 + { 76 + struct cpu_thread_data *data = arg; 77 + 78 + sigaddset(&data->sigset, IPI_SIGNAL); 79 + sigaddset(&data->sigset, SIGIO); 80 + 81 + if (sigprocmask(SIG_SETMASK, &data->sigset, NULL) < 0) 82 + panic("Failed to restore the signal mask, errno = %d", errno); 83 + 84 + kfree(data); 85 + longjmp(*switch_buf, 1); 86 + 87 + /* unreachable */ 88 + printk(UM_KERN_ERR "impossible long jump!"); 89 + fatal_sigsegv(); 90 + } 91 + 92 + int os_send_ipi(int cpu, int vector) 93 + { 94 + union sigval value = { .sival_int = vector }; 95 + 96 + return pthread_sigqueue(cpu_threads[cpu], IPI_SIGNAL, value); 97 + } 98 + 99 + static void __local_ipi_set(int enable) 100 + { 101 + sigset_t sigset; 102 + 103 + sigemptyset(&sigset); 104 + sigaddset(&sigset, IPI_SIGNAL); 105 + 106 + if (sigprocmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) 107 + panic("%s: sigprocmask failed, errno = %d", __func__, errno); 108 + } 109 + 110 + void os_local_ipi_enable(void) 111 + { 112 + __local_ipi_set(1); 113 + } 114 + 115 + void os_local_ipi_disable(void) 116 + { 117 + __local_ipi_set(0); 118 + } 119 + 120 + static void ipi_sig_handler(int sig, siginfo_t *si, void *uc) 121 + { 122 + int save_errno = errno; 123 + 124 + signals_enabled = 0; 125 + um_trace_signals_off(); 126 + 127 + uml_ipi_handler(si->si_value.sival_int); 128 + 129 + um_trace_signals_on(); 130 + signals_enabled = 1; 131 + 132 + errno = save_errno; 133 + } 134 + 135 + void __init os_init_smp(void) 136 + { 137 + struct sigaction action = { 138 + .sa_sigaction = ipi_sig_handler, 139 + .sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART, 140 + }; 141 + 142 + sigfillset(&action.sa_mask); 143 + 144 + if (sigaction(IPI_SIGNAL, &action, NULL) < 0) 145 + panic("%s: sigaction failed, errno = %d", __func__, errno); 146 + 147 + cpu_threads[0] = pthread_self(); 148 + }
+4 -50
arch/um/os-Linux/start_up.c
··· 22 22 #include <asm/unistd.h> 23 23 #include <init.h> 24 24 #include <os.h> 25 + #include <smp.h> 25 26 #include <kern_util.h> 26 27 #include <mem_user.h> 27 28 #include <ptrace_user.h> ··· 482 481 fatal("SECCOMP userspace requested but not functional!\n"); 483 482 } 484 483 484 + if (uml_ncpus > 1) 485 + fatal("SMP is not supported with PTRACE userspace.\n"); 486 + 485 487 using_seccomp = 0; 486 488 check_ptrace(); 487 489 ··· 492 488 if (init_pid_registers(pid)) 493 489 fatal("Failed to initialize default registers"); 494 490 stop_ptraced_child(pid, 1); 495 - } 496 - 497 - int __init parse_iomem(char *str, int *add) 498 - { 499 - struct iomem_region *new; 500 - struct stat64 buf; 501 - char *file, *driver; 502 - int fd, size; 503 - 504 - driver = str; 505 - file = strchr(str,','); 506 - if (file == NULL) { 507 - os_warn("parse_iomem : failed to parse iomem\n"); 508 - goto out; 509 - } 510 - *file = '\0'; 511 - file++; 512 - fd = open(file, O_RDWR, 0); 513 - if (fd < 0) { 514 - perror("parse_iomem - Couldn't open io file"); 515 - goto out; 516 - } 517 - 518 - if (fstat64(fd, &buf) < 0) { 519 - perror("parse_iomem - cannot stat_fd file"); 520 - goto out_close; 521 - } 522 - 523 - new = malloc(sizeof(*new)); 524 - if (new == NULL) { 525 - perror("Couldn't allocate iomem_region struct"); 526 - goto out_close; 527 - } 528 - 529 - size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); 530 - 531 - *new = ((struct iomem_region) { .next = iomem_regions, 532 - .driver = driver, 533 - .fd = fd, 534 - .size = size, 535 - .phys = 0, 536 - .virt = 0 }); 537 - iomem_regions = new; 538 - iomem_size += new->size + UM_KERN_PAGE_SIZE; 539 - 540 - return 0; 541 - out_close: 542 - close(fd); 543 - out: 544 - return 1; 545 491 }
+60 -18
arch/um/os-Linux/time.c
··· 11 11 #include <errno.h> 12 12 #include <signal.h> 13 13 #include <time.h> 14 + #include <sys/signalfd.h> 14 15 #include <sys/time.h> 15 16 #include <kern_util.h> 16 17 #include <os.h> 18 + #include <smp.h> 17 19 #include <string.h> 20 + #include "internal.h" 18 21 19 - static timer_t event_high_res_timer = 0; 22 + static timer_t event_high_res_timer[CONFIG_NR_CPUS] = { 0 }; 20 23 21 24 static inline long long timespec_to_ns(const struct timespec *ts) 22 25 { ··· 34 31 return timespec_to_ns(&realtime_tp); 35 32 } 36 33 34 + #ifndef sigev_notify_thread_id 35 + #define sigev_notify_thread_id _sigev_un._tid 36 + #endif 37 + 37 38 /** 38 39 * os_timer_create() - create an new posix (interval) timer 39 40 */ 40 41 int os_timer_create(void) 41 42 { 42 - timer_t *t = &event_high_res_timer; 43 + int cpu = uml_curr_cpu(); 44 + timer_t *t = &event_high_res_timer[cpu]; 45 + struct sigevent sev = { 46 + .sigev_notify = SIGEV_THREAD_ID, 47 + .sigev_signo = SIGALRM, 48 + .sigev_value.sival_ptr = t, 49 + .sigev_notify_thread_id = gettid(), 50 + }; 43 51 44 - if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 52 + if (timer_create(CLOCK_MONOTONIC, &sev, t) == -1) 45 53 return -1; 46 54 47 55 return 0; 48 56 } 49 57 50 - int os_timer_set_interval(unsigned long long nsecs) 58 + int os_timer_set_interval(int cpu, unsigned long long nsecs) 51 59 { 52 60 struct itimerspec its; 53 61 ··· 68 54 its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 69 55 its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 70 56 71 - if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 57 + if (timer_settime(event_high_res_timer[cpu], 0, &its, NULL) == -1) 72 58 return -errno; 73 59 74 60 return 0; 75 61 } 76 62 77 - int os_timer_one_shot(unsigned long long nsecs) 63 + int os_timer_one_shot(int cpu, unsigned long long nsecs) 78 64 { 79 65 struct itimerspec its = { 80 66 .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, ··· 84 70 .it_interval.tv_nsec = 0, // we cheat here 85 71 }; 86 72 87 - timer_settime(event_high_res_timer, 0, &its, NULL); 73 + timer_settime(event_high_res_timer[cpu], 0, &its, NULL); 88 74 return 0; 89 75 } 90 76 91 77 /** 92 78 * os_timer_disable() - disable the posix (interval) timer 79 + * @cpu: the CPU for which the timer is to be disabled 93 80 */ 94 - void os_timer_disable(void) 81 + void os_timer_disable(int cpu) 95 82 { 96 83 struct itimerspec its; 97 84 98 85 memset(&its, 0, sizeof(struct itimerspec)); 99 - timer_settime(event_high_res_timer, 0, &its, NULL); 86 + timer_settime(event_high_res_timer[cpu], 0, &its, NULL); 100 87 } 101 88 102 89 long long os_nsecs(void) ··· 108 93 return timespec_to_ns(&ts); 109 94 } 110 95 96 + static __thread int wake_signals; 97 + 98 + void os_idle_prepare(void) 99 + { 100 + sigset_t set; 101 + 102 + sigemptyset(&set); 103 + sigaddset(&set, SIGALRM); 104 + sigaddset(&set, IPI_SIGNAL); 105 + 106 + /* 107 + * We need to use signalfd rather than sigsuspend in idle sleep 108 + * because the IPI signal is a real-time signal that carries data, 109 + * and unlike handling SIGALRM, we cannot simply flag it in 110 + * signals_pending. 111 + */ 112 + wake_signals = signalfd(-1, &set, SFD_CLOEXEC); 113 + if (wake_signals < 0) 114 + panic("Failed to create signal FD, errno = %d", errno); 115 + } 116 + 111 117 /** 112 118 * os_idle_sleep() - sleep until interrupted 113 119 */ 114 120 void os_idle_sleep(void) 115 121 { 116 - struct itimerspec its; 117 - sigset_t set, old; 122 + sigset_t set; 118 123 119 - /* block SIGALRM while we analyze the timer state */ 124 + /* 125 + * Block SIGALRM while performing the need_resched check. 126 + * Note that, because IRQs are disabled, the IPI signal is 127 + * already blocked. 128 + */ 120 129 sigemptyset(&set); 121 130 sigaddset(&set, SIGALRM); 122 - sigprocmask(SIG_BLOCK, &set, &old); 131 + sigprocmask(SIG_BLOCK, &set, NULL); 123 132 124 - /* check the timer, and if it'll fire then wait for it */ 125 - timer_gettime(event_high_res_timer, &its); 126 - if (its.it_value.tv_sec || its.it_value.tv_nsec) 127 - sigsuspend(&old); 128 - /* either way, restore the signal mask */ 133 + /* 134 + * Because disabling IRQs does not block SIGALRM, it is also 135 + * necessary to check for any pending timer alarms. 136 + */ 137 + if (!uml_need_resched() && !timer_alarm_pending()) 138 + os_poll(1, &wake_signals); 139 + 140 + /* Restore the signal mask. */ 129 141 sigprocmask(SIG_UNBLOCK, &set, NULL); 130 142 }
-6
arch/um/os-Linux/user_syms.c
··· 31 31 EXPORT_SYMBOL(memset); 32 32 #endif 33 33 34 - #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA 35 - /* needed for __access_ok() */ 36 - EXPORT_SYMBOL(vsyscall_ehdr); 37 - EXPORT_SYMBOL(vsyscall_end); 38 - #endif 39 - 40 34 #ifdef _FORTIFY_SOURCE 41 35 extern int __sprintf_chk(char *str, int flag, size_t len, const char *format); 42 36 EXPORT_SYMBOL(__sprintf_chk);
+3 -4
arch/x86/um/Kconfig
··· 8 8 9 9 config UML_X86 10 10 def_bool y 11 - select ARCH_BINFMT_ELF_EXTRA_PHDRS if X86_32 11 + select ARCH_USE_QUEUED_RWLOCKS 12 + select ARCH_USE_QUEUED_SPINLOCKS 12 13 select DCACHE_WORD_ACCESS 13 14 select HAVE_EFFICIENT_UNALIGNED_ACCESS 15 + select UML_SUBARCH_SUPPORTS_SMP if X86_CX8 14 16 15 17 config 64BIT 16 18 bool "64-bit kernel" if "$(SUBARCH)" = "x86" ··· 32 30 select MODULES_USE_ELF_RELA 33 31 34 32 config ARCH_HAS_SC_SIGNALS 35 - def_bool !64BIT 36 - 37 - config ARCH_REUSE_HOST_VSYSCALL_AREA 38 33 def_bool !64BIT 39 34 40 35 config GENERIC_HWEIGHT
+2 -3
arch/x86/um/Makefile
··· 13 13 ptrace.o ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 14 14 stub_segv.o \ 15 15 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ 16 - mem_$(BITS).o subarch.o os-Linux/ 16 + subarch.o os-Linux/ 17 17 18 18 ifeq ($(CONFIG_X86_32),y) 19 19 20 20 obj-y += syscalls_32.o 21 - obj-$(CONFIG_ELF_CORE) += elfcore.o 22 21 23 22 subarch-y = ../lib/string_32.o ../lib/atomic64_32.o ../lib/atomic64_cx8_32.o 24 23 subarch-y += ../lib/cmpxchg8b_emu.o ../lib/atomic64_386_32.o ··· 26 27 27 28 else 28 29 29 - obj-y += syscalls_64.o vdso/ 30 + obj-y += mem_64.o syscalls_64.o vdso/ 30 31 31 32 subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o \ 32 33 ../lib/memmove_64.o ../lib/memset_64.o
+5 -34
arch/x86/um/asm/elf.h
··· 68 68 pr_reg[16] = PT_REGS_SS(regs); \ 69 69 } while (0); 70 70 71 - extern char * elf_aux_platform; 72 - #define ELF_PLATFORM (elf_aux_platform) 73 - 74 - extern unsigned long vsyscall_ehdr; 75 - extern unsigned long vsyscall_end; 76 - extern unsigned long __kernel_vsyscall; 77 - 78 - /* 79 - * This is the range that is readable by user mode, and things 80 - * acting like user mode such as get_user_pages. 81 - */ 82 - #define FIXADDR_USER_START vsyscall_ehdr 83 - #define FIXADDR_USER_END vsyscall_end 84 - 85 - 86 - /* 87 - * Architecture-neutral AT_ values in 0-17, leave some room 88 - * for more of them, start the x86-specific ones at 32. 89 - */ 90 - #define AT_SYSINFO 32 91 - #define AT_SYSINFO_EHDR 33 92 - 93 - #define ARCH_DLINFO \ 94 - do { \ 95 - if ( vsyscall_ehdr ) { \ 96 - NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall); \ 97 - NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr); \ 98 - } \ 99 - } while (0) 71 + #define ELF_PLATFORM_FALLBACK "i586" 100 72 101 73 #else 102 74 ··· 149 177 (pr_reg)[25] = 0; \ 150 178 (pr_reg)[26] = 0; 151 179 152 - #define ELF_PLATFORM "x86_64" 153 - 154 - /* No user-accessible fixmap addresses, i.e. vsyscall */ 155 - #define FIXADDR_USER_START 0 156 - #define FIXADDR_USER_END 0 180 + #define ELF_PLATFORM_FALLBACK "x86_64" 157 181 158 182 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 159 183 struct linux_binprm; ··· 177 209 178 210 extern long elf_aux_hwcap; 179 211 #define ELF_HWCAP (elf_aux_hwcap) 212 + 213 + extern char *elf_aux_platform; 214 + #define ELF_PLATFORM (elf_aux_platform ?: ELF_PLATFORM_FALLBACK) 180 215 181 216 #define SET_PERSONALITY(ex) do {} while(0) 182 217
+8
arch/x86/um/asm/spinlock.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __ASM_UM_SPINLOCK_H 3 + #define __ASM_UM_SPINLOCK_H 4 + 5 + #include <asm/qspinlock.h> 6 + #include <asm/qrwlock.h> 7 + 8 + #endif /* __ASM_UM_SPINLOCK_H */
-78
arch/x86/um/elfcore.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/elf.h> 3 - #include <linux/elfcore.h> 4 - #include <linux/coredump.h> 5 - #include <linux/fs.h> 6 - #include <linux/mm.h> 7 - 8 - #include <asm/elf.h> 9 - 10 - 11 - Elf32_Half elf_core_extra_phdrs(struct coredump_params *cprm) 12 - { 13 - return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0; 14 - } 15 - 16 - int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset) 17 - { 18 - if ( vsyscall_ehdr ) { 19 - const struct elfhdr *const ehdrp = 20 - (struct elfhdr *) vsyscall_ehdr; 21 - const struct elf_phdr *const phdrp = 22 - (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); 23 - int i; 24 - Elf32_Off ofs = 0; 25 - 26 - for (i = 0; i < ehdrp->e_phnum; ++i) { 27 - struct elf_phdr phdr = phdrp[i]; 28 - 29 - if (phdr.p_type == PT_LOAD) { 30 - ofs = phdr.p_offset = offset; 31 - offset += phdr.p_filesz; 32 - } else { 33 - phdr.p_offset += ofs; 34 - } 35 - phdr.p_paddr = 0; /* match other core phdrs */ 36 - if (!dump_emit(cprm, &phdr, sizeof(phdr))) 37 - return 0; 38 - } 39 - } 40 - return 1; 41 - } 42 - 43 - int elf_core_write_extra_data(struct coredump_params *cprm) 44 - { 45 - if ( vsyscall_ehdr ) { 46 - const struct elfhdr *const ehdrp = 47 - (struct elfhdr *) vsyscall_ehdr; 48 - const struct elf_phdr *const phdrp = 49 - (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); 50 - int i; 51 - 52 - for (i = 0; i < ehdrp->e_phnum; ++i) { 53 - if (phdrp[i].p_type == PT_LOAD) { 54 - void *addr = (void *) phdrp[i].p_vaddr; 55 - size_t filesz = phdrp[i].p_filesz; 56 - if (!dump_emit(cprm, addr, filesz)) 57 - return 0; 58 - } 59 - } 60 - } 61 - return 1; 62 - } 63 - 64 - size_t elf_core_extra_data_size(struct coredump_params *cprm) 65 - { 66 - if ( vsyscall_ehdr ) { 67 - const struct elfhdr *const ehdrp = 68 - (struct elfhdr *)vsyscall_ehdr; 69 - const struct elf_phdr *const phdrp = 70 - (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); 71 - int i; 72 - 73 - for (i = 0; i < ehdrp->e_phnum; ++i) 74 - if (phdrp[i].p_type == PT_LOAD) 75 - return (size_t) phdrp[i].p_filesz; 76 - } 77 - return 0; 78 - }
-50
arch/x86/um/mem_32.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> 4 - */ 5 - 6 - #include <linux/mm.h> 7 - #include <asm/elf.h> 8 - 9 - static struct vm_area_struct gate_vma; 10 - 11 - static int __init gate_vma_init(void) 12 - { 13 - if (!FIXADDR_USER_START) 14 - return 0; 15 - 16 - vma_init(&gate_vma, NULL); 17 - gate_vma.vm_start = FIXADDR_USER_START; 18 - gate_vma.vm_end = FIXADDR_USER_END; 19 - vm_flags_init(&gate_vma, VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC); 20 - gate_vma.vm_page_prot = PAGE_READONLY; 21 - 22 - return 0; 23 - } 24 - __initcall(gate_vma_init); 25 - 26 - struct vm_area_struct *get_gate_vma(struct mm_struct *mm) 27 - { 28 - return FIXADDR_USER_START ? &gate_vma : NULL; 29 - } 30 - 31 - int in_gate_area_no_mm(unsigned long addr) 32 - { 33 - if (!FIXADDR_USER_START) 34 - return 0; 35 - 36 - if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) 37 - return 1; 38 - 39 - return 0; 40 - } 41 - 42 - int in_gate_area(struct mm_struct *mm, unsigned long addr) 43 - { 44 - struct vm_area_struct *vma = get_gate_vma(mm); 45 - 46 - if (!vma) 47 - return 0; 48 - 49 - return (addr >= vma->vm_start) && (addr < vma->vm_end); 50 - }
-17
arch/x86/um/shared/sysdep/kernel-offsets.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <linux/stddef.h> 3 - #include <linux/sched.h> 4 - #include <linux/elf.h> 5 - #include <linux/crypto.h> 6 - #include <linux/kbuild.h> 7 - #include <linux/audit.h> 8 - #include <asm/mman.h> 9 - #include <asm/seccomp.h> 10 - 11 - /* workaround for a warning with -Wmissing-prototypes */ 12 - void foo(void); 13 - 14 - void foo(void) 15 - { 16 - #include <common-offsets.h> 17 - }
+2 -5
arch/x86/um/vdso/Makefile
··· 3 3 # Building vDSO images for x86. 4 4 # 5 5 6 - VDSO64-y := y 7 - 8 - vdso-install-$(VDSO64-y) += vdso.so 9 - 6 + vdso-install-y += vdso.so 10 7 11 8 # files to link into the vdso 12 9 vobjs-y := vdso-note.o um_vdso.o 13 10 14 11 # files to link into kernel 15 - obj-$(VDSO64-y) += vdso.o vma.o 12 + obj-y += vdso.o vma.o 16 13 17 14 vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) 18 15
+3 -27
arch/x86/um/vdso/um_vdso.c
··· 9 9 /* Disable profiling for userspace code */ 10 10 #define DISABLE_BRANCH_PROFILING 11 11 12 + #include <vdso/gettime.h> 12 13 #include <linux/time.h> 13 - #include <linux/getcpu.h> 14 14 #include <asm/unistd.h> 15 15 16 - /* workaround for -Wmissing-prototypes warnings */ 17 - int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts); 18 - int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); 19 - __kernel_old_time_t __vdso_time(__kernel_old_time_t *t); 20 - long __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused); 21 - 22 - int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) 16 + int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) 23 17 { 24 18 long ret; 25 19 ··· 24 30 25 31 return ret; 26 32 } 27 - int clock_gettime(clockid_t, struct __kernel_old_timespec *) 33 + int clock_gettime(clockid_t, struct __kernel_timespec *) 28 34 __attribute__((weak, alias("__vdso_clock_gettime"))); 29 35 30 36 int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) ··· 52 58 return secs; 53 59 } 54 60 __kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__vdso_time"))); 55 - 56 - long 57 - __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused) 58 - { 59 - /* 60 - * UML does not support SMP, we can cheat here. :) 61 - */ 62 - 63 - if (cpu) 64 - *cpu = 0; 65 - if (node) 66 - *node = 0; 67 - 68 - return 0; 69 - } 70 - 71 - long getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *tcache) 72 - __attribute__((weak, alias("__vdso_getcpu")));
-2
arch/x86/um/vdso/vdso.lds.S
··· 22 22 __vdso_clock_gettime; 23 23 gettimeofday; 24 24 __vdso_gettimeofday; 25 - getcpu; 26 - __vdso_getcpu; 27 25 time; 28 26 __vdso_time; 29 27 local: *;
+1 -11
arch/x86/um/vdso/vma.c
··· 10 10 #include <asm/elf.h> 11 11 #include <linux/init.h> 12 12 13 - static unsigned int __read_mostly vdso_enabled = 1; 14 13 unsigned long um_vdso_addr; 15 14 static struct page *um_vdso; 16 15 ··· 24 25 25 26 um_vdso = alloc_page(GFP_KERNEL); 26 27 if (!um_vdso) 27 - goto oom; 28 + panic("Cannot allocate vdso\n"); 28 29 29 30 copy_page(page_address(um_vdso), vdso_start); 30 31 31 32 return 0; 32 - 33 - oom: 34 - printk(KERN_ERR "Cannot allocate vdso\n"); 35 - vdso_enabled = 0; 36 - 37 - return -ENOMEM; 38 33 } 39 34 subsys_initcall(init_vdso); 40 35 ··· 40 47 .name = "[vdso]", 41 48 .pages = &um_vdso, 42 49 }; 43 - 44 - if (!vdso_enabled) 45 - return 0; 46 50 47 51 if (mmap_write_lock_killable(mm)) 48 52 return -EINTR;
+1 -33
fs/hostfs/hostfs.h
··· 3 3 #define __UM_FS_HOSTFS 4 4 5 5 #include <os.h> 6 + #include <generated/asm-offsets.h> 6 7 7 - /* 8 - * These are exactly the same definitions as in fs.h, but the names are 9 - * changed so that this file can be included in both kernel and user files. 10 - */ 11 - 12 - #define HOSTFS_ATTR_MODE 1 13 - #define HOSTFS_ATTR_UID 2 14 - #define HOSTFS_ATTR_GID 4 15 - #define HOSTFS_ATTR_SIZE 8 16 - #define HOSTFS_ATTR_ATIME 16 17 - #define HOSTFS_ATTR_MTIME 32 18 - #define HOSTFS_ATTR_CTIME 64 19 - #define HOSTFS_ATTR_ATIME_SET 128 20 - #define HOSTFS_ATTR_MTIME_SET 256 21 - 22 - /* This one is unused by hostfs. */ 23 - #define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ 24 - #define HOSTFS_ATTR_ATTR_FLAG 1024 25 - 26 - /* 27 - * If you are very careful, you'll notice that these two are missing: 28 - * 29 - * #define ATTR_KILL_SUID 2048 30 - * #define ATTR_KILL_SGID 4096 31 - * 32 - * and this is because they were added in 2.5 development. 33 - * Actually, they are not needed by most ->setattr() methods - they are set by 34 - * callers of notify_change() to notify that the setuid/setgid bits must be 35 - * dropped. 36 - * notify_change() will delete those flags, make sure attr->ia_valid & ATTR_MODE 37 - * is on, and remove the appropriate bits from attr->ia_mode (attr is a 38 - * "struct iattr *"). -BlaisorBlade 39 - */ 40 8 struct hostfs_timespec { 41 9 long long tv_sec; 42 10 long long tv_nsec;
+3
include/asm-generic/percpu.h
··· 2 2 #ifndef _ASM_GENERIC_PERCPU_H_ 3 3 #define _ASM_GENERIC_PERCPU_H_ 4 4 5 + #ifndef __ASSEMBLER__ 6 + 5 7 #include <linux/compiler.h> 6 8 #include <linux/threads.h> 7 9 #include <linux/percpu-defs.h> ··· 559 557 this_cpu_generic_cmpxchg(pcp, oval, nval) 560 558 #endif 561 559 560 + #endif /* __ASSEMBLER__ */ 562 561 #endif /* _ASM_GENERIC_PERCPU_H_ */