um: Add SMP support
v3 cover um: Add SMP support
From: Tiwei Bie <[email protected]>
This series adds initial symmetric multi-processing (SMP) support to UML. With this support, it is now possible for users to tell UML to start multiple virtual CPUs, each represented as a separate host thread.
In UML, kthreads and normal threads (when running in kernel mode) can be scheduled and executed simultaneously on different virtual CPUs. However, the userspace code of normal threads currently still runs within their respective single-threaded stubs.
So SMP within the kernel is supported. SMP across different processes in userspace is also supported. Currently, the limitation is that multi-threading within the same process does not yet support true SMP in userspace, because it would require converting the stub into a multi-threaded implementation, which is not covered in this series.
Extending the stub to support true SMP in userspace within the same process could be done later and requires careful design. It may be better to handle it in a follow-up series.
Here are some steps to try out SMP support in UML:
1. Build UML with CONFIG_SMP=y and, for example, CONFIG_NR_CPUS=8.
2. Launch a UML instance with, for example, 8 virtual CPUs.
$ ./linux mem=16G ncpus=8 seccomp=on init=/bin/sh ubd0=$your_rootfs_image
v3:
- Fix need_resched based idle sleep; (Johannes)
- Remove getcpu support from the vdso on UML/x86; (Johannes)
- Describe 'cpu' parameter of os_timer_disable; ([email protected])
- Misc fixes and cleanups;
v2 (https://lore.kernel.org/all/[email protected]/):
- Implement IPI based on RT signal; (Johannes)
- Fix raw_smp_processor_id() for non-SMP case; (Johannes)
- Add sparse check for turnstile; (Johannes)
- Implement spinlock in $SUBARCH;
- Fix potential race on stub's siginfo;
- Rewrite AP bring-up (e.g. switch to generic idle thread);
- Misc fixes and cleanups;
v1: https://lore.kernel.org/all/[email protected]/
RFC: https://lore.kernel.org/all/[email protected]/
Tiwei Bie (7):
um: Turn signals_* into thread-local variables
um: Determine sleep based on need_resched()
um: Define timers on a per-CPU basis
um: Add initial SMP support
um: vdso: Remove getcpu support on x86
asm-generic: percpu: Add assembly guard
um: Enable SMP support on x86
.../core/generic-idle-thread/arch-support.txt | 2 +- arch/um/Kconfig | 46 +++- arch/um/include/asm/current.h | 5 +- arch/um/include/asm/hardirq.h | 24 +- arch/um/include/asm/irqflags.h | 4 +- arch/um/include/asm/mmu.h | 10 + arch/um/include/asm/pgtable.h | 2 + arch/um/include/asm/smp.h | 15 +- arch/um/include/linux/smp-internal.h | 17 ++ arch/um/include/linux/time-internal.h | 3 + arch/um/include/shared/kern_util.h | 2 + arch/um/include/shared/longjmp.h | 3 +- arch/um/include/shared/os.h | 24 +- arch/um/include/shared/skas/mm_id.h | 5 + arch/um/include/shared/smp.h | 20 ++ arch/um/kernel/Makefile | 1 + arch/um/kernel/irq.c | 27 +- arch/um/kernel/ksyms.c | 2 +- arch/um/kernel/mem.c | 2 + arch/um/kernel/process.c | 17 +- arch/um/kernel/skas/mmu.c | 33 ++- arch/um/kernel/skas/process.c | 7 +- arch/um/kernel/smp.c | 241 ++++++++++++++++++ arch/um/kernel/time.c | 58 +++-- arch/um/kernel/tlb.c | 5 +- arch/um/kernel/trap.c | 2 +- arch/um/kernel/um_arch.c | 25 +- arch/um/os-Linux/Makefile | 4 +- arch/um/os-Linux/internal.h | 13 + arch/um/os-Linux/main.c | 5 +- arch/um/os-Linux/process.c | 20 ++ arch/um/os-Linux/signal.c | 46 +++- arch/um/os-Linux/skas/process.c | 22 +- arch/um/os-Linux/smp.c | 148 +++++++++++ arch/um/os-Linux/start_up.c | 4 + arch/um/os-Linux/time.c | 78 ++++-- arch/x86/um/Kconfig | 3 + arch/x86/um/asm/spinlock.h | 8 + arch/x86/um/vdso/um_vdso.c | 20 -- arch/x86/um/vdso/vdso.lds.S | 2 - include/asm-generic/percpu.h | 3 + 41 files changed, 870 insertions(+), 108 deletions(-) create mode 100644 arch/um/include/linux/smp-internal.h create mode 100644 arch/um/include/shared/smp.h create mode 100644 arch/um/kernel/smp.c create mode 100644 arch/um/os-Linux/smp.c create mode 100644 arch/x86/um/asm/spinlock.h
base-commit: e66ae377fe219c98d3d5b8a0d35da4413a5390ca
Signature · 1 line
2.34.1
PATCH v3 1/7 um: Turn signals_* into thread-local variables
From: Tiwei Bie <[email protected]>
Turn signals_enabled, signals_pending and signals_active into thread-local variables. This enables us to control and track signals independently on each CPU thread. This is a preparation for adding SMP support.
--- arch/um/include/asm/irqflags.h | 4 ++-- arch/um/include/shared/longjmp.h | 3 +-- arch/um/include/shared/os.h | 1 + arch/um/kernel/ksyms.c | 2 +- arch/um/os-Linux/signal.c | 11 ++++++++--- 5 files changed, 13 insertions(+), 8 deletions(-)
arch/um/include/asm/irqflags.h +2 -2
@@ -2,7 +2,7 @@#ifndef __UM_IRQFLAGS_H#define __UM_IRQFLAGS_H -extern int signals_enabled; +int um_get_signals (void );int um_set_signals (int enable);void block_signals (void );void unblock_signals (void );
@@ -10,7 +10,7 @@ void unblock_signals(void);#define arch_local_save_flags arch_local_save_flagsstatic inline unsigned long arch_local_save_flags (void ) { -return signals_enabled; +return um_get_signals (); }#define arch_local_irq_restore arch_local_irq_restore
arch/um/include/shared/longjmp.h +1 -2
@@ -5,7 +5,6 @@#include <sysdep/archsetjmp.h> #include <os.h> -extern int signals_enabled;extern int setjmp (jmp_buf );extern void longjmp (jmp_buf ,int );
@@ -15,7 +14,7 @@ extern void longjmp(jmp_buf, int);#define UML_SETJMP (buf) ({ \ int n, enable; \ - enable = *(volatile int *)&signals_enabled; \ + enable = um_get_signals(); \ n = setjmp(*buf); \ if(n != 0) \ um_set_signals_trace(enable); \
arch/um/include/shared/os.h +1 -0
@@ -243,6 +243,7 @@ extern void send_sigio_to_self(void);extern int change_sig (int signal,int on);extern void block_signals (void );extern void unblock_signals (void ); +extern int um_get_signals (void );extern int um_set_signals (int enable);extern int um_set_signals_trace (int enable);extern void deliver_alarm (void );
arch/um/kernel/ksyms.c +1 -1
@@ -6,8 +6,8 @@#include <linux/module.h> #include <os.h> +EXPORT_SYMBOL (um_get_signals);EXPORT_SYMBOL (um_set_signals); -EXPORT_SYMBOL (signals_enabled);EXPORT_SYMBOL (os_stat_fd);EXPORT_SYMBOL (os_stat_file);
arch/um/os-Linux/signal.c +8 -3
@@ -68,12 +68,12 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)#define SIGCHLD_BIT 2#define SIGCHLD_MASK (1 << SIGCHLD_BIT) -int signals_enabled; +static __threadint signals_enabled;#if IS_ENABLED (CONFIG_UML_TIME_TRAVEL_SUPPORT )static int signals_blocked, signals_blocked_pending;#endif -static unsigned int signals_pending; -static unsigned int signals_active =0 ; +static __threadunsigned int signals_pending; +static __threadunsigned int signals_active;static void sig_handler (int sig,struct siginfo *si,mcontext_t *mc) {
@@ -342,6 +342,11 @@ void unblock_signals(void) } } +int um_get_signals (void ) +{ +return signals_enabled; +} +int um_set_signals (int enable) {int ret;
Signature · 1 line
2.34.1
PATCH v3 2/7 um: Determine sleep based on need_resched()
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
With SMP and NO_HZ enabled, the CPU may still need to sleep even if the timer is disarmed. Switch to deciding whether to sleep based on pending resched. Additionally, because disabling IRQs does not block SIGALRM, it is also necessary to check for any pending timer alarms. This is a preparation for adding SMP support.
--- arch/um/include/shared/kern_util.h | 1 + arch/um/kernel/process.c | 5 +++++ arch/um/os-Linux/internal.h | 5 +++++ arch/um/os-Linux/signal.c | 6 ++++++ arch/um/os-Linux/time.c | 15 +++++++++------ 5 files changed, 26 insertions(+), 6 deletions(-)
arch/um/include/shared/kern_util.h +1 -0
@@ -55,6 +55,7 @@ extern int __uml_cant_sleep(void);extern int get_current_pid (void );extern int copy_from_user_proc (void *to,void *from,int size);extern char *uml_strdup (const char *string); +int uml_need_resched (void );extern unsigned long to_irq_stack (unsigned long *mask_out);extern unsigned long from_irq_stack (int nested);
arch/um/kernel/process.c +5 -0
@@ -225,6 +225,11 @@ int __uml_cant_sleep(void) {/* Is in_interrupt() really needed? */ } +int uml_need_resched (void ) +{ +return need_resched (); +} +extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;void do_uml_exitcalls (void )
arch/um/os-Linux/internal.h +5 -0
@@ -15,6 +15,11 @@ void scan_elf_aux(char **envp);*/ void check_tmpexec (void ); +/* +* signal.c +*/ +int timer_alarm_pending (void ); +/* * skas/process.c */
arch/um/os-Linux/signal.c +6 -0
@@ -20,6 +20,7 @@#include <um_malloc.h> #include <sys/ucontext.h> #include <timetravel.h> +#include "internal.h" void (*sig_info[NSIG ])(int ,struct siginfo *,struct uml_pt_regs *,void *mc) = { [SIGTRAP ] = relay_signal,
@@ -159,6 +160,11 @@ void timer_set_signal_handler(void)set_handler (SIGALRM ); } +int timer_alarm_pending (void ) +{ +return !!(signals_pending &SIGALRM_MASK ); +} +void set_sigstack (void *sig_stack,int size) {stack_t stack = {
arch/um/os-Linux/time.c +9 -6
@@ -15,6 +15,7 @@#include <kern_util.h> #include <os.h> #include <string.h> +#include "internal.h" static timer_t event_high_res_timer =0 ;
@@ -98,18 +99,20 @@ long long os_nsecs(void)*/ void os_idle_sleep (void ) { -struct itimerspec its;sigset_t set, old; -/* block SIGALRM while we analyze the timer state */ +/* Block SIGALRM while performing the need_resched check. */ sigemptyset (&set);sigaddset (&set,SIGALRM );sigprocmask (SIG_BLOCK , &set, &old); -/* check the timer, and if it'll fire then wait for it */ -timer_gettime (event_high_res_timer, &its); -if (its.it_value.tv_sec || its.it_value.tv_nsec) +/* +* Because disabling IRQs does not block SIGALRM, it is also +* necessary to check for any pending timer alarms. +*/ +if (!uml_need_resched () && !timer_alarm_pending ())sigsuspend (&old); -/* either way, restore the signal mask */ + +/* Restore the signal mask. */ sigprocmask (SIG_UNBLOCK , &set,NULL ); }
Signature · 1 line
2.34.1
PATCH v3 3/7 um: Define timers on a per-CPU basis
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
Define timers on a per-CPU basis to enable each CPU to have its own timer. This is a preparation for adding SMP support.
--- arch/um/include/linux/time-internal.h | 3 ++ arch/um/include/shared/os.h | 6 +-- arch/um/kernel/irq.c | 2 +- arch/um/kernel/time.c | 58 +++++++++++++++++++-------- arch/um/os-Linux/main.c | 2 +- arch/um/os-Linux/time.c | 29 +++++++++----- 6 files changed, 69 insertions(+), 31 deletions(-)
arch/um/include/linux/time-internal.h +3 -0
@@ -90,4 +90,7 @@ extern unsigned long tt_extra_sched_jiffies;* which is intentional since we really shouldn't link it in that case. */ void time_travel_ndelay (unsigned long nsec); + +int um_setup_timer (void ); +#endif /* __TIMER_INTERNAL_H__ */
arch/um/include/shared/os.h +3 -3
@@ -269,9 +269,9 @@ extern void os_warn(const char *fmt, ...)/* time.c */ extern void os_idle_sleep (void );extern int os_timer_create (void ); -extern int os_timer_set_interval (unsigned long long nsecs); -extern int os_timer_one_shot (unsigned long long nsecs); -extern void os_timer_disable (void ); +extern int os_timer_set_interval (int cpu,unsigned long long nsecs); +extern int os_timer_one_shot (int cpu,unsigned long long nsecs); +extern void os_timer_disable (int cpu);extern long long os_persistent_clock_emulation (void );extern long long os_nsecs (void );
arch/um/kernel/irq.c +1 -1
@@ -683,7 +683,7 @@ void __init init_IRQ(void) {int i; -irq_set_chip_and_handler (TIMER_IRQ , &alarm_irq_type, handle_edge_irq); +irq_set_chip_and_handler (TIMER_IRQ , &alarm_irq_type, handle_percpu_irq);for (i =1 ; i <UM_LAST_SIGNAL_IRQ ; i++)irq_set_chip_and_handler (i, &normal_irq_type, handle_edge_irq);
arch/um/kernel/time.c +41 -17
170 lines not on this page · raw message
arch/um/os-Linux/main.c +1 -1
@@ -171,7 +171,7 @@ int __init main(int argc, char **argv, char **envp)*/ /* stop timers and set timer signal to be ignored */ -os_timer_disable (); +os_timer_disable (0 );/* disable SIGIO for the fds and set SIGIO to be ignored */ err =deactivate_all_fds ();
arch/um/os-Linux/time.c +20 -9
@@ -17,7 +17,7 @@#include <string.h> #include "internal.h" -static timer_t event_high_res_timer =0 ; +static timer_t event_high_res_timer[CONFIG_NR_CPUS ] = {0 };static inline long long timespec_to_ns (const struct timespec *ts) {
@@ -32,20 +32,30 @@ long long os_persistent_clock_emulation(void)return timespec_to_ns (&realtime_tp); } +#ifndef sigev_notify_thread_id +#define sigev_notify_thread_id _sigev_un._tid +#endif +/** * os_timer_create() - create an new posix (interval) timer */ int os_timer_create (void ) { -timer_t *t = &event_high_res_timer; +timer_t *t = &event_high_res_timer[0 ]; +struct sigevent sev = { + .sigev_notify =SIGEV_THREAD_ID , + .sigev_signo =SIGALRM , + .sigev_value.sival_ptr = t, + .sigev_notify_thread_id =gettid (), + }; -if (timer_create (CLOCK_MONOTONIC ,NULL , t) ==-1 ) +if (timer_create (CLOCK_MONOTONIC , &sev, t) ==-1 )return -1 ;return 0 ; } -int os_timer_set_interval (unsigned long long nsecs) +int os_timer_set_interval (int cpu,unsigned long long nsecs) {struct itimerspec its;
@@ -55,13 +65,13 @@ int os_timer_set_interval(unsigned long long nsecs) its.it_interval.tv_sec = nsecs /UM_NSEC_PER_SEC ; its.it_interval.tv_nsec = nsecs %UM_NSEC_PER_SEC ; -if (timer_settime (event_high_res_timer,0 , &its,NULL ) ==-1 ) +if (timer_settime (event_high_res_timer[cpu],0 , &its,NULL ) ==-1 )return -errno;return 0 ; } -int os_timer_one_shot (unsigned long long nsecs) +int os_timer_one_shot (int cpu,unsigned long long nsecs) {struct itimerspec its = { .it_value.tv_sec = nsecs /UM_NSEC_PER_SEC ,
@@ -71,19 +81,20 @@ int os_timer_one_shot(unsigned long long nsecs) .it_interval.tv_nsec = 0, // we cheat here }; -timer_settime (event_high_res_timer,0 , &its,NULL ); +timer_settime (event_high_res_timer[cpu],0 , &its,NULL );return 0 ; }/** * os_timer_disable() - disable the posix (interval) timer +* @cpu: the CPU for which the timer is to be disabled */ -void os_timer_disable (void ) +void os_timer_disable (int cpu) {struct itimerspec its;memset (&its,0 ,sizeof (struct itimerspec )); -timer_settime (event_high_res_timer,0 , &its,NULL ); +timer_settime (event_high_res_timer[cpu],0 , &its,NULL ); }long long os_nsecs (void )
Signature · 1 line
2.34.1
PATCH v3 4/7 um: Add initial SMP support
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
Add initial symmetric multi-processing (SMP) support to UML. With this support enabled, users can tell UML to start multiple virtual processors, each represented as a separate host thread.
In UML, kthreads and normal threads (when running in kernel mode) can be scheduled and executed simultaneously on different virtual processors. However, the userspace code of normal threads still runs within their respective single-threaded stubs.
That is, SMP support is currently available both within the kernel and across different processes, but still remains limited within threads of the same process in userspace.
--- .../core/generic-idle-thread/arch-support.txt | 2 +- arch/um/Kconfig | 46 +++- arch/um/include/asm/current.h | 5 +- arch/um/include/asm/hardirq.h | 24 +- arch/um/include/asm/mmu.h | 10 + arch/um/include/asm/pgtable.h | 2 + arch/um/include/asm/smp.h | 15 +- arch/um/include/linux/smp-internal.h | 17 ++ arch/um/include/shared/kern_util.h | 1 + arch/um/include/shared/os.h | 17 ++ arch/um/include/shared/skas/mm_id.h | 5 + arch/um/include/shared/smp.h | 20 ++ arch/um/kernel/Makefile | 1 + arch/um/kernel/irq.c | 25 ++ arch/um/kernel/mem.c | 2 + arch/um/kernel/process.c | 12 +- arch/um/kernel/skas/mmu.c | 33 ++- arch/um/kernel/skas/process.c | 7 +- arch/um/kernel/smp.c | 241 ++++++++++++++++++ arch/um/kernel/tlb.c | 5 +- arch/um/kernel/trap.c | 2 +- arch/um/kernel/um_arch.c | 25 +- arch/um/os-Linux/Makefile | 4 +- arch/um/os-Linux/internal.h | 8 + arch/um/os-Linux/main.c | 3 +- arch/um/os-Linux/process.c | 20 ++ arch/um/os-Linux/signal.c | 31 ++- arch/um/os-Linux/skas/process.c | 22 +- arch/um/os-Linux/smp.c | 148 +++++++++++ arch/um/os-Linux/start_up.c | 4 + arch/um/os-Linux/time.c | 38 ++- 31 files changed, 751 insertions(+), 44 deletions(-) create mode 100644 arch/um/include/linux/smp-internal.h create mode 100644 arch/um/include/shared/smp.h create mode 100644 arch/um/kernel/smp.c create mode 100644 arch/um/os-Linux/smp.c
Documentation/features/core/generic-idle-thread/arch-support.txt +1 -1
@@ -24,7 +24,7 @@ | s390: | ok | | sh: | ok | | sparc: | ok | - | um: | TODO | + | um: | ok | | x86: | ok | | xtensa: | ok | -----------------------
arch/um/Kconfig +43 -3
65 lines not on this page · raw message
arch/um/include/asm/current.h +3 -2
@@ -7,15 +7,16 @@#ifndef __ASSEMBLER__ +#include <shared/smp.h> +struct task_struct ;extern struct task_struct *cpu_tasks[NR_CPUS ]; static __always_inline struct task_struct *get_current(void) { -return cpu_tasks[0 ]; +return cpu_tasks[uml_curr_cpu ()]; } -#define current get_current()#endif /* __ASSEMBLER__ */
arch/um/include/asm/hardirq.h +23 -1
@@ -2,8 +2,30 @@#ifndef __ASM_UM_HARDIRQ_H#define __ASM_UM_HARDIRQ_H -#include <asm-generic/hardirq.h> +#include <linux/cache.h> +#include <linux/threads.h> #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 +typedef struct { +unsigned int __softirq_pending; +#if IS_ENABLED (CONFIG_SMP ) +unsigned int irq_resched_count; +unsigned int irq_call_count; +#endif +}____cacheline_aligned irq_cpustat_t ; + +DECLARE_PER_CPU_SHARED_ALIGNED (irq_cpustat_t, irq_stat); + +#define __ARCH_IRQ_STAT + +#define inc_irq_stat (member) this_cpu_inc(irq_stat.member) + +#include <linux/irq.h> + +static inline void ack_bad_irq (unsigned int irq) +{ +pr_crit ("unexpected IRQ trap at vector %02x\n" , irq); +} +#endif /* __ASM_UM_HARDIRQ_H */
arch/um/include/asm/mmu.h +10 -0
@@ -7,16 +7,26 @@#define __ARCH_UM_MMU_H#include "linux/types.h" +#include <linux/mutex.h> +#include <linux/spinlock.h> #include <mm_id.h> typedef struct mm_context {struct mm_id id; +struct mutex turnstile;struct list_head list;/* Address range in need of a TLB sync */ +spinlock_t sync_tlb_lock;unsigned long sync_tlb_range_from;unsigned long sync_tlb_range_to; }mm_context_t ; +#define INIT_MM_CONTEXT (mm) \ + .context = { \ + .turnstile = __MUTEX_INITIALIZER(mm.context.turnstile), \ + .sync_tlb_lock = __SPIN_LOCK_INITIALIZER(mm.context.sync_tlb_lock), \ + } +#endif
arch/um/include/asm/pgtable.h +2 -0
@@ -225,6 +225,8 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)static inline void um_tlb_mark_sync (struct mm_struct *mm,unsigned long start,unsigned long end) { +guard (spinlock_irqsave)(&mm->context.sync_tlb_lock); +if (!mm->context.sync_tlb_range_to) { mm->context.sync_tlb_range_from = start; mm->context.sync_tlb_range_to = end;
arch/um/include/asm/smp.h +14 -1
@@ -2,6 +2,19 @@#ifndef __UM_SMP_H#define __UM_SMP_H -#define hard_smp_processor_id () 0 +#if IS_ENABLED (CONFIG_SMP ) + +#include <linux/cpumask.h> +#include <shared/smp.h> + +#define raw_smp_processor_id () uml_curr_cpu() + +void arch_smp_send_reschedule (int cpu); + +void arch_send_call_function_single_ipi (int cpu); + +void arch_send_call_function_ipi_mask (const struct cpumask *mask); + +#endif /* CONFIG_SMP */ #endif
arch/um/include/linux/smp-internal.h new file +17 -0
@@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __UM_SMP_INTERNAL_H +#define __UM_SMP_INTERNAL_H + +#if IS_ENABLED (CONFIG_SMP ) + +void prefill_possible_map (void ); + +#else /* !CONFIG_SMP */ + +static inline void prefill_possible_map (void ) { } + +#endif /* CONFIG_SMP */ + +extern char cpu_irqstacks[NR_CPUS ][THREAD_SIZE ]__aligned(THREAD_SIZE) ; + +#endif /* __UM_SMP_INTERNAL_H */
arch/um/include/shared/kern_util.h +1 -0
@@ -14,6 +14,7 @@ struct siginfo;extern int uml_exitcode;extern int kmalloc_ok; +extern int kmalloc_disabled[];#define UML_ROUND_UP (addr) \ ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK)
arch/um/include/shared/os.h +17 -0
@@ -216,6 +216,9 @@ extern int can_drop_memory(void);void os_set_pdeathsig (void ); +int os_futex_wait (void *uaddr,unsigned int val); +int os_futex_wake (void *uaddr); +/* execvp.c */ extern int execvp_noalloc (char *buf,const char *file,char *const argv[]);/* helper.c */
@@ -267,6 +270,7 @@ extern void os_warn(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));/* time.c */ +void os_idle_prepare (void );extern void os_idle_sleep (void );extern int os_timer_create (void );extern int os_timer_set_interval (int cpu,unsigned long long nsecs);
@@ -339,4 +343,17 @@ extern void um_trace_signals_off(void);/* time-travel */ extern void deliver_time_travel_irqs (void ); +/* smp.c */ +#if IS_ENABLED (CONFIG_SMP ) +void os_init_smp (void ); +int os_start_cpu_thread (int cpu); +void os_start_secondary (void *arg,jmp_buf *switch_buf); +int os_send_ipi (int cpu,int vector); +void os_local_ipi_enable (void ); +void os_local_ipi_disable (void ); +#else /* !CONFIG_SMP */ +static inline void os_local_ipi_enable (void ) { } +static inline void os_local_ipi_disable (void ) { } +#endif /* CONFIG_SMP */ +#endif
arch/um/include/shared/skas/mm_id.h +5 -0
@@ -6,6 +6,8 @@#ifndef __MM_ID_H#define __MM_ID_H +#include <linux/compiler_types.h> +#define STUB_MAX_FDS 4 struct mm_id {
@@ -19,6 +21,9 @@ struct mm_id {int syscall_fd_map[STUB_MAX_FDS ]; }; +void enter_turnstile(struct mm_id *mm_id) __acquires(turnstile); +void exit_turnstile(struct mm_id *mm_id) __releases(turnstile); +void notify_mm_kill (int pid);#endif
arch/um/include/shared/smp.h new file +20 -0
@@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __UM_SHARED_SMP_H +#define __UM_SHARED_SMP_H + +#if IS_ENABLED (CONFIG_SMP ) + +extern int uml_ncpus; + +int uml_curr_cpu (void ); +void uml_start_secondary (void *opaque); +void uml_ipi_handler (int vector); + +#else /* !CONFIG_SMP */ + +#define uml_ncpus 1 +#define uml_curr_cpu () 0 + +#endif /* CONFIG_SMP */ + +#endif /* __UM_SHARED_SMP_H */
arch/um/kernel/Makefile +1 -0
@@ -25,6 +25,7 @@ obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_OF) += dtb.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_SMP) += smp.o USER_OBJS := config.o
arch/um/kernel/irq.c +25 -0
@@ -22,6 +22,9 @@#include <irq_kern.h> #include <linux/time-internal.h> +DEFINE_PER_CPU_SHARED_ALIGNED (irq_cpustat_t, irq_stat); + +#define irq_stats (x) (&per_cpu(irq_stat, x))/* When epoll triggers we do not know why it did so * we can also have different IRQs for read and write.
@@ -701,3 +704,25 @@ void sigchld_handler(int sig, struct siginfo *unused_si, {do_IRQ (SIGCHLD_IRQ , regs); } + +/* +* /proc/interrupts printing for arch specific interrupts +*/ +int arch_show_interrupts (struct seq_file *p,int prec) +{ +#if IS_ENABLED (CONFIG_SMP ) +int cpu; + +seq_printf (p,"%*s: " , prec,"RES" ); +for_each_online_cpu (cpu) +seq_printf (p,"%10u " ,irq_stats (cpu)->irq_resched_count); +seq_puts (p," Rescheduling interrupts\n" ); + +seq_printf (p,"%*s: " , prec,"CAL" ); +for_each_online_cpu (cpu) +seq_printf (p,"%10u " ,irq_stats (cpu)->irq_call_count); +seq_puts (p," Function call interrupts\n" ); +#endif + +return 0 ; +}
arch/um/kernel/mem.c +2 -0
@@ -53,6 +53,8 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD];/* Initialized at boot time, and readonly after that */ int kmalloc_ok =0 ; +int kmalloc_disabled[NR_CPUS ]; +/* Used during early boot */ static unsigned long brk_end;
arch/um/kernel/process.c +9 -3
@@ -185,11 +185,12 @@ int copy_thread(struct task_struct * p, const struct kernel_clone_args *args)void initial_thread_cb (void (*proc)(void *),void *arg) { -int save_kmalloc_ok = kmalloc_ok; +int cpu =raw_smp_processor_id (); +int save_kmalloc = kmalloc_disabled[cpu]; - kmalloc_ok =0 ; + kmalloc_disabled[cpu] =1 ;initial_thread_cb_skas (proc, arg); - kmalloc_ok = save_kmalloc_ok; + kmalloc_disabled[cpu] = save_kmalloc; } int arch_dup_task_struct(struct task_struct *dst,
@@ -220,6 +221,11 @@ void arch_cpu_idle(void)um_idle_sleep (); } +void arch_cpu_idle_prepare (void ) +{ +os_idle_prepare (); +} +int __uml_cant_sleep (void ) {return in_atomic () ||irqs_disabled () ||in_interrupt ();/* Is in_interrupt() really needed? */
arch/um/kernel/skas/mmu.c +25 -8
@@ -23,17 +23,36 @@ static_assert(sizeof(struct stub_data) == STUB_DATA_PAGES * UM_KERN_PAGE_SIZE);static spinlock_t mm_list_lock;static struct list_head mm_list; +void enter_turnstile (struct mm_id *mm_id)__acquires (turnstile) +{ + struct mm_context *ctx = container_of(mm_id, struct mm_context, id); + +mutex_lock (&ctx->turnstile); +} + +void exit_turnstile (struct mm_id *mm_id)__releases (turnstile) +{ + struct mm_context *ctx = container_of(mm_id, struct mm_context, id); + +mutex_unlock (&ctx->turnstile); +} +int init_new_context (struct task_struct *task,struct mm_struct *mm) {struct mm_id *new_id = &mm->context.id;unsigned long stack =0 ;int ret = -ENOMEM ; +mutex_init (&mm->context.turnstile); +spin_lock_init (&mm->context.sync_tlb_lock); + stack =__get_free_pages (GFP_KERNEL | __GFP_ZERO,ilog2 (STUB_DATA_PAGES ));if (stack ==0 ) goto out; new_id->stack = stack; + new_id->syscall_data_len =0 ; + new_id->syscall_fd_num =0 ; scoped_guard(spinlock_irqsave, &mm_list_lock) {/* Insert into list, used for lookups when the child dies */
@@ -73,6 +92,9 @@ void destroy_context(struct mm_struct *mm)return ; } + scoped_guard(spinlock_irqsave, &mm_list_lock) +list_del (&mm->context.list); +if (mmu->id.pid >0 ) {os_kill_ptraced_process (mmu->id.pid,1 ); mmu->id.pid =-1 ;
@@ -82,10 +104,6 @@ void destroy_context(struct mm_struct *mm)os_close_file (mmu->id.sock);free_pages (mmu->id.stack,ilog2 (STUB_DATA_PAGES )); - -guard (spinlock_irqsave)(&mm_list_lock); - -list_del (&mm->context.list); }static irqreturn_t mm_sigchld_irq (int irq,void * dev)
@@ -110,12 +128,11 @@ static irqreturn_t mm_sigchld_irq(int irq, void* dev)/* Marks the MM as dead */ mm_context->id.pid =-1 ; -/* -* NOTE: If SMP is implemented, a futex_wake -* needs to be added here. -*/ stub_data = (void *)mm_context->id.stack; stub_data->futex =FUTEX_IN_KERN ; +#if IS_ENABLED (CONFIG_SMP ) +os_futex_wake (&stub_data->futex); +#endif /* * NOTE: Currently executing syscalls by
arch/um/kernel/skas/process.c +4 -3
@@ -7,6 +7,7 @@#include <linux/sched/mm.h> #include <linux/sched/task_stack.h> #include <linux/sched/task.h> +#include <linux/smp-internal.h> #include <asm/tlbflush.h>
@@ -26,12 +27,12 @@ static int __init start_kernel_proc(void *unused)return 0 ; } -static char cpu0_irqstack[THREAD_SIZE ]__aligned(THREAD_SIZE) ; +char cpu_irqstacks[NR_CPUS ][THREAD_SIZE ]__aligned(THREAD_SIZE) ;int __init start_uml (void ) { -stack_protections ((unsigned long ) &cpu0_irqstack); -set_sigstack (cpu0_irqstack,THREAD_SIZE ); +stack_protections ((unsigned long ) &cpu_irqstacks[0 ]); +set_sigstack (cpu_irqstacks[0 ],THREAD_SIZE );init_new_thread_signals ();
arch/um/kernel/smp.c new file +241 -0
241 lines not on this page · raw message
arch/um/kernel/tlb.c +4 -1
@@ -162,9 +162,11 @@ int um_tlb_sync(struct mm_struct *mm) {pgd_t *pgd;struct vm_ops ops; -unsigned long addr = mm->context.sync_tlb_range_from, next; +unsigned long addr, next;int ret =0 ; +guard (spinlock_irqsave)(&mm->context.sync_tlb_lock); +if (mm->context.sync_tlb_range_to ==0 )return 0 ;
@@ -177,6 +179,7 @@ int um_tlb_sync(struct mm_struct *mm) ops.unmap = unmap; } + addr = mm->context.sync_tlb_range_from; pgd =pgd_offset (mm, addr); do { next = pgd_addr_end(addr, mm->context.sync_tlb_range_to);
arch/um/kernel/trap.c +1 -1
@@ -316,7 +316,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,if (!is_user && regs) current->thread.segv_regs = container_of(regs, struct pt_regs, regs); -if (!is_user && init_mm.context.sync_tlb_range_to) { +if (!is_user && address >= start_vm && address < end_vm) {/* * Kernel has pending updates from set_ptes that were not * flushed yet. Syncing them should fix the pagefault (if not
arch/um/kernel/um_arch.c +23 -2
@@ -19,6 +19,7 @@#include <linux/kmsg_dump.h> #include <linux/suspend.h> #include <linux/random.h> +#include <linux/smp-internal.h> #include <asm/processor.h> #include <asm/cpufeature.h>
@@ -71,6 +72,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) {int i =0 ; +#if IS_ENABLED (CONFIG_SMP ) + i = (uintptr_t ) v -1 ; +if (!cpu_online (i)) +return 0 ; +#endif +seq_printf (m,"processor\t: %d\n" , i);seq_printf (m,"vendor_id\t: User Mode Linux\n" );seq_printf (m,"model name\t: UML\n" );
@@ -87,13 +94,14 @@ static int show_cpuinfo(struct seq_file *m, void *v) loops_per_jiffy/(500000 /HZ ), (loops_per_jiffy/(5000/HZ)) % 100); -return 0 ; }static void *c_start (struct seq_file *m,loff_t *pos) { -return *pos < nr_cpu_ids ? &boot_cpu_data + *pos :NULL ; +if (*pos < nr_cpu_ids) +return (void *)(uintptr_t )(*pos +1 ); +return NULL ; }static void *c_next (struct seq_file *m,void *v,loff_t *pos)
@@ -421,6 +429,7 @@ void __init setup_arch(char **cmdline_p)strscpy (boot_command_line, command_line,COMMAND_LINE_SIZE ); *cmdline_p = command_line;setup_hostinfo (host_info,sizeof host_info); +prefill_possible_map ();if (os_getrandom (rng_seed,sizeof (rng_seed),0 ) ==sizeof (rng_seed)) {add_bootloader_randomness (rng_seed,sizeof (rng_seed));
@@ -455,6 +464,18 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) { } +#if IS_ENABLED (CONFIG_SMP ) +void alternatives_smp_module_add (struct module *mod,char *name, +void *locks,void *locks_end, +void *text,void *text_end) +{ +} + +void alternatives_smp_module_del (struct module *mod) +{ +} +#endif +void *text_poke (void *addr,const void *opcode,size_t len) {/*
arch/um/os-Linux/Makefile +3 -1
@@ -16,8 +16,10 @@ CFLAGS_main.o += -Wno-frame-larger-than obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o +obj-$(CONFIG_SMP) += smp.o + USER_OBJS := $(user-objs-y) elf_aux.o execvp.o file.o helper.o irq.o \ main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ - tty.o umid.o util.o + tty.o umid.o util.o smp.o include $(srctree)/arch/um/scripts/Makefile.rules
arch/um/os-Linux/internal.h +8 -0
@@ -4,6 +4,7 @@#include <mm_id.h> #include <stub-data.h> +#include <signal.h> /* * elf_aux.c
@@ -18,6 +19,7 @@ void check_tmpexec(void);/* * signal.c */ +extern __threadint signals_enabled;int timer_alarm_pending (void );/*
@@ -25,4 +27,10 @@ int timer_alarm_pending(void);*/ void wait_stub_done (int pid);void wait_stub_done_seccomp (struct mm_id *mm_idp,int running,int wait_sigsys); + +/* +* smp.c +*/ +#define IPI_SIGNAL SIGRTMIN +#endif /* __UM_OS_LINUX_INTERNAL_H */
arch/um/os-Linux/main.c +2 -1
@@ -16,6 +16,7 @@#include <init.h> #include <kern_util.h> #include <os.h> +#include <smp.h> #include <um_malloc.h> #include "internal.h"
@@ -207,7 +208,7 @@ void *__wrap_malloc(int size) {void *ret; -if (!kmalloc_ok) +if (!kmalloc_ok || kmalloc_disabled[uml_curr_cpu ()])return __real_malloc (size);else if (size <=UM_KERN_PAGE_SIZE )/* finding contiguous pages can be hard*/
arch/um/os-Linux/process.c +20 -0
@@ -10,6 +10,8 @@#include <errno.h> #include <signal.h> #include <fcntl.h> +#include <limits.h> +#include <linux/futex.h> #include <sys/mman.h> #include <sys/ptrace.h> #include <sys/prctl.h>
@@ -189,3 +191,21 @@ void os_set_pdeathsig(void) {prctl (PR_SET_PDEATHSIG ,SIGKILL ); } + +int os_futex_wait (void *uaddr,unsigned int val) +{ +int r; + +CATCH_EINTR (r =syscall (__NR_futex, uaddr,FUTEX_WAIT , val, +NULL ,NULL ,0 )); +return r <0 ? -errno : r; +} + +int os_futex_wake (void *uaddr) +{ +int r; + +CATCH_EINTR (r =syscall (__NR_futex, uaddr,FUTEX_WAKE ,INT_MAX , +NULL ,NULL ,0 )); +return r <0 ? -errno : r; +}
arch/um/os-Linux/signal.c +26 -5
@@ -69,7 +69,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)#define SIGCHLD_BIT 2#define SIGCHLD_MASK (1 << SIGCHLD_BIT) -static __threadint signals_enabled; +__threadint signals_enabled;#if IS_ENABLED (CONFIG_UML_TIME_TRAVEL_SUPPORT )static int signals_blocked, signals_blocked_pending;#endif
@@ -259,9 +259,29 @@ int change_sig(int signal, int on)return 0 ; } -void block_signals (void ) +static inline void __block_signals (void ) { +if (!signals_enabled) +return ; + +os_local_ipi_disable (); +barrier (); signals_enabled =0 ; +} + +static inline void __unblock_signals (void ) +{ +if (signals_enabled) +return ; + + signals_enabled =1 ; +barrier (); +os_local_ipi_enable (); +} + +void block_signals (void ) +{ +__block_signals ();/* * This must return with signals disabled, so this barrier * ensures that writes are flushed out before the return.
@@ -278,7 +298,8 @@ void unblock_signals(void)if (signals_enabled ==1 )return ; - signals_enabled =1 ; +__unblock_signals (); +#if IS_ENABLED (CONFIG_UML_TIME_TRAVEL_SUPPORT )deliver_time_travel_irqs ();#endif
@@ -312,7 +333,7 @@ void unblock_signals(void)* tracing that happens inside the handlers we call for the * pending signals will mess up the tracing state. */ - signals_enabled =0 ; +__block_signals ();um_trace_signals_off ();/*
@@ -344,7 +365,7 @@ void unblock_signals(void)/* Re-enable signals and trace that we're doing so. */ um_trace_signals_on (); - signals_enabled =1 ; +__unblock_signals (); } }
arch/um/os-Linux/skas/process.c +16 -6
@@ -553,7 +553,7 @@ extern unsigned long tt_extra_sched_jiffies;void userspace (struct uml_pt_regs *regs) {int err, status, op; -siginfo_t si_ptrace; +siginfo_t si_local;siginfo_t *si;int sig;
@@ -563,6 +563,13 @@ void userspace(struct uml_pt_regs *regs)while (1 ) {struct mm_id *mm_id =current_mm_id (); +/* +* At any given time, only one CPU thread can enter the +* turnstile to operate on the same stub process, including +* executing stub system calls (mmap and munmap). +*/ +enter_turnstile (mm_id); +/* * When we are in time-travel mode, userspace can theoretically * do a *lot* of work without being scheduled. The problem with
@@ -630,9 +637,10 @@ void userspace(struct uml_pt_regs *regs) }if (proc_data->si_offset >sizeof (proc_data->sigstack) -sizeof (*si)) -panic ("%s - Invalid siginfo offset from child" , - __func__); - si = (void *)&proc_data->sigstack[proc_data->si_offset]; +panic ("%s - Invalid siginfo offset from child" , __func__); + + si = &si_local; +memcpy (si, &proc_data->sigstack[proc_data->si_offset],sizeof (*si)); regs->is_user =1 ;
@@ -728,8 +736,8 @@ void userspace(struct uml_pt_regs *regs)case SIGFPE :case SIGWINCH :ptrace (PTRACE_GETSIGINFO , pid,0 , - (struct siginfo *)&si_ptrace); - si = &si_ptrace; + (struct siginfo *)&si_local); + si = &si_local;break ;default : si =NULL ;
@@ -740,6 +748,8 @@ void userspace(struct uml_pt_regs *regs) } } +exit_turnstile (mm_id); +UPT_SYSCALL_NR (regs) =-1 ;/* Assume: It's not a syscall */ if (sig) {
arch/um/os-Linux/smp.c new file +148 -0
148 lines not on this page · raw message
arch/um/os-Linux/start_up.c +4 -0
@@ -22,6 +22,7 @@#include <asm/unistd.h> #include <init.h> #include <os.h> +#include <smp.h> #include <kern_util.h> #include <mem_user.h> #include <ptrace_user.h>
@@ -481,6 +482,9 @@ void __init os_early_checks(void)fatal ("SECCOMP userspace requested but not functional!\n" ); } +if (uml_ncpus >1 ) +fatal ("SMP is not supported with PTRACE userspace.\n" ); + using_seccomp =0 ;check_ptrace ();
arch/um/os-Linux/time.c +33 -5
@@ -11,9 +11,11 @@#include <errno.h> #include <signal.h> #include <time.h> +#include <sys/signalfd.h> #include <sys/time.h> #include <kern_util.h> #include <os.h> +#include <smp.h> #include <string.h> #include "internal.h"
@@ -41,7 +43,8 @@ long long os_persistent_clock_emulation(void)*/ int os_timer_create (void ) { -timer_t *t = &event_high_res_timer[0 ]; +int cpu =uml_curr_cpu (); +timer_t *t = &event_high_res_timer[cpu];struct sigevent sev = { .sigev_notify =SIGEV_THREAD_ID , .sigev_signo =SIGALRM ,
@@ -105,24 +108,49 @@ long long os_nsecs(void)return timespec_to_ns (&ts); } +static __threadint wake_signals; + +void os_idle_prepare (void ) +{ +sigset_t set; + +sigemptyset (&set); +sigaddset (&set,SIGALRM ); +sigaddset (&set,IPI_SIGNAL ); + +/* +* We need to use signalfd rather than sigsuspend in idle sleep +* because the IPI signal is a real‑time signal that carries data, +* and unlike handling SIGALRM, we cannot simply flag it in +* signals_pending. +*/ + wake_signals =signalfd (-1 , &set,SFD_CLOEXEC ); +if (wake_signals <0 ) +panic ("Failed to create signal FD, errno = %d" , errno); +} +/** * os_idle_sleep() - sleep until interrupted */ void os_idle_sleep (void ) { -sigset_t set, old; +sigset_t set; -/* Block SIGALRM while performing the need_resched check. */ +/* +* Block SIGALRM while performing the need_resched check. +* Note that, because IRQs are disabled, the IPI signal is +* already blocked. +*/ sigemptyset (&set);sigaddset (&set,SIGALRM ); -sigprocmask (SIG_BLOCK , &set, &old); +sigprocmask (SIG_BLOCK , &set,NULL );/* * Because disabling IRQs does not block SIGALRM, it is also * necessary to check for any pending timer alarms. */ if (!uml_need_resched () && !timer_alarm_pending ()) -sigsuspend (&old); +os_poll (1 , &wake_signals);/* Restore the signal mask. */ sigprocmask (SIG_UNBLOCK , &set,NULL );
Signature · 1 line
2.34.1
PATCH v3 5/7 um: vdso: Remove getcpu support on x86
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
We are going to support SMP on UML/x86, so we can't hard code the CPU and NUMA node in __vdso_getcpu() anymore. Let's just remove it and let applications fall back to the syscall.
--- arch/x86/um/vdso/um_vdso.c | 20 -------------------- arch/x86/um/vdso/vdso.lds.S | 2 -- 2 files changed, 22 deletions(-)
arch/x86/um/vdso/um_vdso.c +0 -20
@@ -10,14 +10,12 @@#define DISABLE_BRANCH_PROFILING #include <linux/time.h> -#include <linux/getcpu.h> #include <asm/unistd.h> /* workaround for -Wmissing-prototypes warnings */ int __vdso_clock_gettime (clockid_t clock,struct __kernel_old_timespec *ts);int __vdso_gettimeofday (struct __kernel_old_timeval *tv,struct timezone *tz);__kernel_old_time_t __vdso_time (__kernel_old_time_t *t); -long __vdso_getcpu (unsigned int *cpu,unsigned int *node,struct getcpu_cache *unused);int __vdso_clock_gettime (clockid_t clock,struct __kernel_old_timespec *ts) {
@@ -58,21 +56,3 @@ __kernel_old_time_t __vdso_time(__kernel_old_time_t *t)return secs; }__kernel_old_time_t time (__kernel_old_time_t *t) __attribute__((weak,alias ("__vdso_time" ))); - -long -__vdso_getcpu (unsigned int *cpu,unsigned int *node,struct getcpu_cache *unused) -{ -/* -* UML does not support SMP, we can cheat here. :) -*/ - -if (cpu) - *cpu =0 ; -if (node) - *node =0 ; - -return 0 ; -} - -long getcpu (unsigned int *cpu,unsigned int *node,struct getcpu_cache *tcache) - __attribute__((weak,alias ("__vdso_getcpu" )));
arch/x86/um/vdso/vdso.lds.S +0 -2
@@ -22,8 +22,6 @@ VERSION { __vdso_clock_gettime; gettimeofday; __vdso_gettimeofday; - getcpu; - __vdso_getcpu; time; __vdso_time; local: *;
Signature · 1 line
2.34.1
PATCH v3 6/7 asm-generic: percpu: Add assembly guard
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
Currently, asm/percpu.h is directly or indirectly included by some assembly files on x86. Some of them (e.g., checksum_32.S) are also used on um. But x86 and um provide different versions of asm/percpu.h -- um uses asm-generic/percpu.h directly.
When SMP is enabled, asm-generic/percpu.h will introduce C code that cannot be assembled. Since asm-generic/percpu.h currently is not designed for use in assembly, and these assembly files do not actually need asm/percpu.h on um, let's add the assembly guard in asm-generic/percpu.h to fix this issue.
--- include/asm-generic/percpu.h | 3 +++ 1 file changed, 3 insertions(+)
include/asm-generic/percpu.h +3 -0
@@ -2,6 +2,8 @@#ifndef _ASM_GENERIC_PERCPU_H_#define _ASM_GENERIC_PERCPU_H_ +#ifndef __ASSEMBLER__ +#include <linux/compiler.h> #include <linux/threads.h> #include <linux/percpu-defs.h>
@@ -557,4 +559,5 @@ do { \ this_cpu_generic_cmpxchg(pcp, oval, nval)#endif +#endif /* __ASSEMBLER__ */ #endif /* _ASM_GENERIC_PERCPU_H_ */
Signature · 1 line
2.34.1
Re: [PATCH v3 6/7] asm-generic: percpu: Add assembly guard
Quoted 13 lines · Tiwei Bie
From: Tiwei Bie <[email protected]>
Currently,
asm/percpu.his directly or indirectly included by some assembly files on x86. Some of them (e.g.,checksum_32.S) are also used on um. But x86 and um provide different versions ofasm/percpu.h-- um usesasm-generic/percpu.hdirectly.When SMP is enabled,
asm-generic/percpu.hwill introduce C code that cannot be assembled. Sinceasm-generic/percpu.hcurrently is not designed for use in assembly, and these assembly files do not actually needasm/percpu.hon um, let's add the assembly guard inasm-generic/percpu.hto fix this issue.
Quoted 3 lines
Have you tried if you can remove the percpu.h dependency from the files that currently include it? In many cases it should be enough to use percpu-defs.h.
If that doesn't work, I have no objections to this patch either.
Re: [PATCH v3 6/7] asm-generic: percpu: Add assembly guard
Quoted 14 lines · Arnd Bergmann
Quoted 13 lines · Tiwei Bie
From: Tiwei Bie <[email protected]>
Currently,
asm/percpu.his directly or indirectly included by some assembly files on x86. Some of them (e.g.,checksum_32.S) are also used on um. But x86 and um provide different versions ofasm/percpu.h-- um usesasm-generic/percpu.hdirectly.When SMP is enabled,
asm-generic/percpu.hwill introduce C code that cannot be assembled. Sinceasm-generic/percpu.hcurrently is not designed for use in assembly, and these assembly files do not actually needasm/percpu.hon um, let's add the assembly guard inasm-generic/percpu.hto fix this issue.
Quoted 7 lines
Quoted 3 lines
Have you tried if you can remove the
percpu.hdependency from the files that currently include it? In many cases it should be enough to usepercpu-defs.h.
It doesn't seem to work. The indirect inclusion of asm/percpu.h comes from asm/nospec-branch.h, which expands DECLARE_PER_CPU() and thus requires asm/percpu.h.
Quoted 4 lines
If that doesn't work, I have no objections to this patch either.
Acked-by Arnd Bergmann <[email protected]>
Thanks! :)
Regards,
Tiwei
PATCH v3 7/7 um: Enable SMP support on x86
In reply to Tiwei BieFrom: Tiwei Bie <[email protected]>
Implement spinlock support for SMP on UML/x86, leveraging x86's spinlock implementation. In addition, to support SMP on CPUs that do not support CX8, some additional work is required. However, considering that such CPUs are already very outdated, and x86 is also removing support for them [1], let's enable SMP support only on CPUs that support CX8.
[1] https://lore.kernel.org/lkml/[email protected]/
--- arch/x86/um/Kconfig | 3 +++ arch/x86/um/asm/spinlock.h | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 arch/x86/um/asm/spinlock.h
arch/x86/um/Kconfig +3 -0
@@ -9,8 +9,11 @@ endmenu config UML_X86 def_bool y select ARCH_BINFMT_ELF_EXTRA_PHDRS if X86_32 + select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USE_QUEUED_SPINLOCKS select DCACHE_WORD_ACCESS select HAVE_EFFICIENT_UNALIGNED_ACCESS + select UML_SUBARCH_SUPPORTS_SMP if X86_CX8 config 64BIT bool "64-bit kernel" if "$(SUBARCH)" = "x86"
arch/x86/um/asm/spinlock.h new file +8 -0
@@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_UM_SPINLOCK_H +#define __ASM_UM_SPINLOCK_H + +#include <asm/qspinlock.h> +#include <asm/qrwlock.h> + +#endif /* __ASM_UM_SPINLOCK_H */
Signature · 1 line
2.34.1