From nobody Thu Dec 18 19:59:05 2025 Received: from out-179.mta0.migadu.com (out-179.mta0.migadu.com [91.218.175.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E69313D8B1 for ; Mon, 27 Oct 2025 00:18:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524319; cv=none; b=XUPV/PaV5Y9f/H/2/8yKw0xAhCCdTHrYDIR1t8X7WH5Ol/ZdtvDjrq/2jOSJ1xD5FRmyrkLgezFC2zDu1y7FL52UGHa0fmuhaD5f8fuBxnXCzUwLHKKCft/OT8RrYTCNjFOJHgo7nOjRZnzS2FmNXHORvTn7nXMrI45+YkezxJE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524319; c=relaxed/simple; bh=GFZt+8mLxgQwtLF02GYQcib0/QKzquioMxG4/Vag5To=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=tXEedEF8O2tESTyyP3yGXfuFll6Ptb0ZD4jqgCpJ3Pk2nkTlm9Ga1Q9cxpgxibbsE5rRTKpTLlLJLQ78NvTebxoSbKZMUmiNYCvD8cw01jIpzTbvw+1P+u6k+v7c4gey7EGVw7rQd2s77pVIy8eHiwiuE+uldKPKuPMoYRaDMxE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=d4RhZ0g+; arc=none smtp.client-ip=91.218.175.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="d4RhZ0g+" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524315; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QjFrwlF759x9QExSvPBA2TAaIUv0ml3JmoT2DaGEPdo=; b=d4RhZ0g+0hgDpoTkj5KARfRZ8GwC9ZHCDLUPcoTGJFnec/pe5+kdAyECOlFdqSV2NWE5hn bVBRqkXxkyGrHiCCXfO2nM5yqnLaLktAN8+avRk+O+9QeBEOh4UBndt259lQRt3lMfZscd 4ozKS3wrPZAsspc0QNPyG32pcoyPd7I= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 1/8] um: Do not disable kmalloc in initial_thread_cb() Date: Mon, 27 Oct 2025 08:18:08 +0800 Message-Id: <20251027001815.1666872-2-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie Currently, initial_thread_cb() temporarily disables kmalloc when it invokes the callback, allowing the callback to bypass kmalloc. This is unnecessary for the current users of initial_thread_cb(), and we should avoid memory allocations that are not under the control of the UML kernel. Therefore, let's stop temporarily disabling kmalloc in initial_thread_cb(). Signed-off-by: Tiwei Bie --- arch/um/kernel/process.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 9c9c66dc45f0..757e21185a0e 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -185,11 +185,7 @@ int copy_thread(struct task_struct * p, const struct k= ernel_clone_args *args) =20 void initial_thread_cb(void (*proc)(void *), void *arg) { - int save_kmalloc_ok =3D kmalloc_ok; - - kmalloc_ok =3D 0; initial_thread_cb_skas(proc, arg); - kmalloc_ok =3D save_kmalloc_ok; } =20 int arch_dup_task_struct(struct task_struct *dst, --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-174.mta0.migadu.com (out-174.mta0.migadu.com [91.218.175.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 213991E9906 for ; Mon, 27 Oct 2025 00:18:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524322; cv=none; b=crCNw6ftT0OH4z6eQzWhaYyTfFav6oXOd1iaPIzIN1RAyRpaQQJWHenrLSPHM8FtORtKvszjOZYcEDyite0vy5XaBXTy7aXMMMRk6nA7r2nWaaQ6MJA6M3AJO/hvSpKwpvc4IQ17wUfeau++WR5yBbGQFRy1i/BRzZsBPkHfhUI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524322; c=relaxed/simple; bh=OW9H3G7kCOMhcU87Zcmzqh32zJnsRj6fi7PQv+wQNF4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=uHTgmhHnvElfxmhwz7hJ7SUUoW2EHOmBNmdYuUaH6WeBkwa48KgxLT7phIg59O4MCsLSJskxnJkKO4QYVp4d1jl0xCg1KUZp57NOXtYVK9mFXWqW/L3PlICTGLGWJcxrdZ+oZuCZOQQU0BD0sDjYpl6SKwXoX9bXvKMP4eL4qYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=fkM9ai0l; arc=none smtp.client-ip=91.218.175.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="fkM9ai0l" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524318; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QSESnP/sa4r5ORTRPvhvwWnuR1/omMMQhE1G5EL1OGY=; b=fkM9ai0lAa8UqXU+xcEiedv2Dy6vnBO1C1mJVEKWzCGSI7MY2MvmP2rwe7J/q8lQ7bFS1i P15rgxxVVWTFotoWX/3l9p318D36F0tco8fAr/iJk3R/AOVV+gRzAxdoxIFupdVgbsaAHC A1dOckJIKXHLkKV9X2CRN9hLK1hV0bo= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 2/8] um: Turn signals_* into thread-local variables Date: Mon, 27 Oct 2025 08:18:09 +0800 Message-Id: <20251027001815.1666872-3-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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. Signed-off-by: Tiwei Bie --- 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(-) diff --git a/arch/um/include/asm/irqflags.h b/arch/um/include/asm/irqflags.h index 1e69ef5bc35e..31e49e0894c5 100644 --- a/arch/um/include/asm/irqflags.h +++ b/arch/um/include/asm/irqflags.h @@ -2,7 +2,7 @@ #ifndef __UM_IRQFLAGS_H #define __UM_IRQFLAGS_H =20 -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_flags static inline unsigned long arch_local_save_flags(void) { - return signals_enabled; + return um_get_signals(); } =20 #define arch_local_irq_restore arch_local_irq_restore diff --git a/arch/um/include/shared/longjmp.h b/arch/um/include/shared/long= jmp.h index 8863319039f3..c53e43d980c8 100644 --- a/arch/um/include/shared/longjmp.h +++ b/arch/um/include/shared/longjmp.h @@ -5,7 +5,6 @@ #include #include =20 -extern int signals_enabled; extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); =20 @@ -15,7 +14,7 @@ extern void longjmp(jmp_buf, int); =20 #define UML_SETJMP(buf) ({ \ int n, enable; \ - enable =3D *(volatile int *)&signals_enabled; \ + enable =3D um_get_signals(); \ n =3D setjmp(*buf); \ if(n !=3D 0) \ um_set_signals_trace(enable); \ diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index b35cc8ce333b..324d4eed3385 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -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); diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index f2fb77da08cf..96314c31e61c 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -6,8 +6,8 @@ #include #include =20 +EXPORT_SYMBOL(um_get_signals); EXPORT_SYMBOL(um_set_signals); -EXPORT_SYMBOL(signals_enabled); =20 EXPORT_SYMBOL(os_stat_fd); EXPORT_SYMBOL(os_stat_file); diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 11f07f498270..58da8c6ece98 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -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) =20 -int signals_enabled; +static __thread int 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 =3D 0; +static __thread unsigned int signals_pending; +static __thread unsigned int signals_active; =20 static void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { @@ -342,6 +342,11 @@ void unblock_signals(void) } } =20 +int um_get_signals(void) +{ + return signals_enabled; +} + int um_set_signals(int enable) { int ret; --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-185.mta0.migadu.com (out-185.mta0.migadu.com [91.218.175.185]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E78161DFD9A for ; Mon, 27 Oct 2025 00:18:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.185 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524325; cv=none; b=gsFgb5QFxkREndMCTacMokfxZHNNq7fYbnrVk+rVzr6x547Z+xA3yNpZOslQSH4JqF3D2HLfNH6ISUEblfJJceF0xdTlb/LEZZyHqyMSJPd1lVgExJFsm53kHRDu1GvYlIuKgB1wWgIq2YMzl3GIoMwEp3lo/BrvLUhzunQ2TXM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524325; c=relaxed/simple; bh=/bytV+P0QzJ2BkHlgOCUL+wKnHuQg6wcFuWibL7DaWQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=X3rGWqN3p9AwBRrvAA0bedWs7B7Izxshw46qpC94JuUedtWoYbIuVPM3xJZfjoUu3tFXsJY1jdWwSLNFPZbWh+aBnSzxWcYMGhgi3p/MSG6XsH/Kz0I8MujsQZkQ/fTXzxNBJRU2jNe9WhHNf9HqNygmTfapOe+0LYNLhk8Bc4w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Q8PZUXJ/; arc=none smtp.client-ip=91.218.175.185 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Q8PZUXJ/" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524320; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3yN0Jw1zCGCU2swiMeoJP4VIvF3PJD+YGhgn1SWJiEQ=; b=Q8PZUXJ/EFYmqfsILLrn33GI2LpzoVpOYBn1f/BIYssTfx9gjrppPCCAZ3n5cmcnPPfYdp i0BIgEY0kHVfH7XF7b5cbEI41wIZu8fxNgRSzhRlsZXWuo9wwWEMn/MTR1sQukRG0goVGX 7R/et7Hpnq1H+UkawmRUWBLvKEViJV8= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 3/8] um: Determine sleep based on need_resched() Date: Mon, 27 Oct 2025 08:18:10 +0800 Message-Id: <20251027001815.1666872-4-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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. Signed-off-by: Tiwei Bie --- 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(-) diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/ke= rn_util.h index 00ca3e12fd9a..3daaa5c4b35d 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -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); =20 extern unsigned long to_irq_stack(unsigned long *mask_out); extern unsigned long from_irq_stack(int nested); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 757e21185a0e..a60230b299da 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -221,6 +221,11 @@ int __uml_cant_sleep(void) { /* Is in_interrupt() really needed? */ } =20 +int uml_need_resched(void) +{ + return need_resched(); +} + extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; =20 void do_uml_exitcalls(void) diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h index 5d8d3b0817a9..c2c7a0dc673c 100644 --- a/arch/um/os-Linux/internal.h +++ b/arch/um/os-Linux/internal.h @@ -15,6 +15,11 @@ void scan_elf_aux(char **envp); */ void check_tmpexec(void); =20 +/* + * signal.c + */ +int timer_alarm_pending(void); + /* * skas/process.c */ diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 58da8c6ece98..554a87dd32cc 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -20,6 +20,7 @@ #include #include #include +#include "internal.h" =20 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *= mc) =3D { [SIGTRAP] =3D relay_signal, @@ -159,6 +160,11 @@ void timer_set_signal_handler(void) set_handler(SIGALRM); } =20 +int timer_alarm_pending(void) +{ + return !!(signals_pending & SIGALRM_MASK); +} + void set_sigstack(void *sig_stack, int size) { stack_t stack =3D { diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 4d5591d96d8c..f3d4547e5227 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -15,6 +15,7 @@ #include #include #include +#include "internal.h" =20 static timer_t event_high_res_timer =3D 0; =20 @@ -98,18 +99,20 @@ long long os_nsecs(void) */ void os_idle_sleep(void) { - struct itimerspec its; sigset_t set, old; =20 - /* 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); =20 - /* 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); } --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-181.mta0.migadu.com (out-181.mta0.migadu.com [91.218.175.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6C64F211A14 for ; Mon, 27 Oct 2025 00:18:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524327; cv=none; b=HL8+BQoTmqOH/cmTH4NshReaUCuubq1rbBWa05Dhbc1QzqBtWKgRh10MRtkRmv5/bh4Fi8+KWe75MwEDMsKrV9LJWzt6QYMh7Cyol5mt03f/srmDV+VmecyivpoVCD/PBYZwPkdiVeCL1HCaSJClP9jgFx4Dssx/EncdGeIXqwo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524327; c=relaxed/simple; bh=bN7JgM0k0U/9inC1tbWjnv1SjLrvbkqAqo6w80vJGaM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gXeykO077fiZjPSsQDL1QuPQNyRFUkhjwAJ6ZxQdplDn8qVyYm9Q07Tu3Gdgus9/4H6FF8PhYLwhcui8pq40NBGaWNDlxFSkDz3guhxNffZHTc9SFRG2XzaEjIntWzoR421OYRvEtiFskh2k88BV8qSK5hOZAp4d7kTk3/bOcr4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=g4By4Xl0; arc=none smtp.client-ip=91.218.175.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="g4By4Xl0" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524323; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rDYOBZP09xty0+mF9o95/f9Ufo6O5DV5hlHkQg1lE/Q=; b=g4By4Xl0oCX/fyJNByU88Qy8RSxlxotPWOqRAtjagupewmtuUkrwa91Zw/IPrutZrVM2D6 1TR8A/Qw9Xb5nwEaAP5xqNsnkLFUrz0LxzDmiwgjeH1Y1zHKPpcea30AeDIrMmmmihiErb BYaaEk4rwnYj9yiR7uoz7gahfTZZKh0= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 4/8] um: Define timers on a per-CPU basis Date: Mon, 27 Oct 2025 08:18:11 +0800 Message-Id: <20251027001815.1666872-5-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie Define timers on a per-CPU basis to enable each CPU to have its own timer. This is a preparation for adding SMP support. Signed-off-by: Tiwei Bie --- 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(-) diff --git a/arch/um/include/linux/time-internal.h b/arch/um/include/linux/= time-internal.h index 138908b999d7..c274eb5ad55e 100644 --- a/arch/um/include/linux/time-internal.h +++ b/arch/um/include/linux/time-internal.h @@ -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__ */ diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 324d4eed3385..0ca6e4548671 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -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); =20 diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index d69d137a0334..e95f6c5a259d 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -683,7 +683,7 @@ void __init init_IRQ(void) { int i; =20 - 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); =20 for (i =3D 1; i < UM_LAST_SIGNAL_IRQ; i++) irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 17da0a870650..b344a36b44eb 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -625,9 +625,10 @@ void time_travel_sleep(void) * controller application. */ unsigned long long next =3D S64_MAX; + int cpu =3D raw_smp_processor_id(); =20 if (time_travel_mode =3D=3D TT_MODE_BASIC) - os_timer_disable(); + os_timer_disable(cpu); =20 time_travel_update_time(next, true); =20 @@ -638,9 +639,9 @@ void time_travel_sleep(void) * This is somewhat wrong - we should get the first * one sooner like the os_timer_one_shot() below... */ - os_timer_set_interval(time_travel_timer_interval); + os_timer_set_interval(cpu, time_travel_timer_interval); } else { - os_timer_one_shot(time_travel_timer_event.time - next); + os_timer_one_shot(cpu, time_travel_timer_event.time - next); } } } @@ -758,6 +759,8 @@ extern u64 time_travel_ext_req(u32 op, u64 time); #define time_travel_del_event(e) do { } while (0) #endif =20 +static struct clock_event_device timer_clockevent[NR_CPUS]; + void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs = *regs) { unsigned long flags; @@ -780,12 +783,14 @@ void timer_handler(int sig, struct siginfo *unused_si= , struct uml_pt_regs *regs) =20 static int itimer_shutdown(struct clock_event_device *evt) { + int cpu =3D evt - &timer_clockevent[0]; + if (time_travel_mode !=3D TT_MODE_OFF) time_travel_del_event(&time_travel_timer_event); =20 if (time_travel_mode !=3D TT_MODE_INFCPU && time_travel_mode !=3D TT_MODE_EXTERNAL) - os_timer_disable(); + os_timer_disable(cpu); =20 return 0; } @@ -793,6 +798,7 @@ static int itimer_shutdown(struct clock_event_device *e= vt) static int itimer_set_periodic(struct clock_event_device *evt) { unsigned long long interval =3D NSEC_PER_SEC / HZ; + int cpu =3D evt - &timer_clockevent[0]; =20 if (time_travel_mode !=3D TT_MODE_OFF) { time_travel_del_event(&time_travel_timer_event); @@ -805,7 +811,7 @@ static int itimer_set_periodic(struct clock_event_devic= e *evt) =20 if (time_travel_mode !=3D TT_MODE_INFCPU && time_travel_mode !=3D TT_MODE_EXTERNAL) - os_timer_set_interval(interval); + os_timer_set_interval(cpu, interval); =20 return 0; } @@ -825,7 +831,7 @@ static int itimer_next_event(unsigned long delta, =20 if (time_travel_mode !=3D TT_MODE_INFCPU && time_travel_mode !=3D TT_MODE_EXTERNAL) - return os_timer_one_shot(delta); + return os_timer_one_shot(raw_smp_processor_id(), delta); =20 return 0; } @@ -835,10 +841,9 @@ static int itimer_one_shot(struct clock_event_device *= evt) return itimer_next_event(0, evt); } =20 -static struct clock_event_device timer_clockevent =3D { +static struct clock_event_device _timer_clockevent =3D { .name =3D "posix-timer", .rating =3D 250, - .cpumask =3D cpu_possible_mask, .features =3D CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_state_shutdown =3D itimer_shutdown, @@ -856,6 +861,9 @@ static struct clock_event_device timer_clockevent =3D { =20 static irqreturn_t um_timer(int irq, void *dev) { + int cpu =3D raw_smp_processor_id(); + struct clock_event_device *evt =3D &timer_clockevent[cpu]; + /* * Interrupt the (possibly) running userspace process, technically this * should only happen if userspace is currently executing. @@ -867,7 +875,7 @@ static irqreturn_t um_timer(int irq, void *dev) get_current()->mm) os_alarm_process(get_current()->mm->context.id.pid); =20 - (*timer_clockevent.event_handler)(&timer_clockevent); + evt->event_handler(evt); =20 return IRQ_HANDLED; } @@ -904,7 +912,24 @@ static struct clocksource timer_clocksource =3D { .flags =3D CLOCK_SOURCE_IS_CONTINUOUS, }; =20 -static void __init um_timer_setup(void) +int um_setup_timer(void) +{ + int cpu =3D raw_smp_processor_id(); + struct clock_event_device *evt =3D &timer_clockevent[cpu]; + int err; + + err =3D os_timer_create(); + if (err) + return err; + + memcpy(evt, &_timer_clockevent, sizeof(*evt)); + evt->cpumask =3D cpumask_of(cpu); + clockevents_register_device(evt); + + return 0; +} + +static void __init um_timer_init(void) { int err; =20 @@ -913,8 +938,8 @@ static void __init um_timer_setup(void) printk(KERN_ERR "register_timer : request_irq failed - " "errno =3D %d\n", -err); =20 - err =3D os_timer_create(); - if (err !=3D 0) { + err =3D um_setup_timer(); + if (err) { printk(KERN_ERR "creation of timer failed - errno =3D %d\n", -err); return; } @@ -924,7 +949,6 @@ static void __init um_timer_setup(void) printk(KERN_ERR "clocksource_register_hz returned %d\n", err); return; } - clockevents_register_device(&timer_clockevent); } =20 void read_persistent_clock64(struct timespec64 *ts) @@ -945,7 +969,7 @@ void read_persistent_clock64(struct timespec64 *ts) void __init time_init(void) { timer_set_signal_handler(); - late_time_init =3D um_timer_setup; + late_time_init =3D um_timer_init; } =20 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT @@ -961,21 +985,21 @@ static int setup_time_travel(char *str) { if (strcmp(str, "=3Dinf-cpu") =3D=3D 0) { time_travel_mode =3D TT_MODE_INFCPU; - timer_clockevent.name =3D "time-travel-timer-infcpu"; + _timer_clockevent.name =3D "time-travel-timer-infcpu"; timer_clocksource.name =3D "time-travel-clock"; return 1; } =20 if (strncmp(str, "=3Dext:", 5) =3D=3D 0) { time_travel_mode =3D TT_MODE_EXTERNAL; - timer_clockevent.name =3D "time-travel-timer-external"; + _timer_clockevent.name =3D "time-travel-timer-external"; timer_clocksource.name =3D "time-travel-clock-external"; return time_travel_connect_external(str + 5); } =20 if (!*str) { time_travel_mode =3D TT_MODE_BASIC; - timer_clockevent.name =3D "time-travel-timer"; + _timer_clockevent.name =3D "time-travel-timer"; timer_clocksource.name =3D "time-travel-clock"; return 1; } diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 3c63ce19e3bf..730723106228 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -171,7 +171,7 @@ int __init main(int argc, char **argv, char **envp) */ =20 /* stop timers and set timer signal to be ignored */ - os_timer_disable(); + os_timer_disable(0); =20 /* disable SIGIO for the fds and set SIGIO to be ignored */ err =3D deactivate_all_fds(); diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index f3d4547e5227..e0197bfe4ac9 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -17,7 +17,7 @@ #include #include "internal.h" =20 -static timer_t event_high_res_timer =3D 0; +static timer_t event_high_res_timer[CONFIG_NR_CPUS] =3D { 0 }; =20 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); } =20 +#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 =3D &event_high_res_timer; + timer_t *t =3D &event_high_res_timer[0]; + struct sigevent sev =3D { + .sigev_notify =3D SIGEV_THREAD_ID, + .sigev_signo =3D SIGALRM, + .sigev_value.sival_ptr =3D t, + .sigev_notify_thread_id =3D gettid(), + }; =20 - if (timer_create(CLOCK_MONOTONIC, NULL, t) =3D=3D -1) + if (timer_create(CLOCK_MONOTONIC, &sev, t) =3D=3D -1) return -1; =20 return 0; } =20 -int os_timer_set_interval(unsigned long long nsecs) +int os_timer_set_interval(int cpu, unsigned long long nsecs) { struct itimerspec its; =20 @@ -55,13 +65,13 @@ int os_timer_set_interval(unsigned long long nsecs) its.it_interval.tv_sec =3D nsecs / UM_NSEC_PER_SEC; its.it_interval.tv_nsec =3D nsecs % UM_NSEC_PER_SEC; =20 - if (timer_settime(event_high_res_timer, 0, &its, NULL) =3D=3D -1) + if (timer_settime(event_high_res_timer[cpu], 0, &its, NULL) =3D=3D -1) return -errno; =20 return 0; } =20 -int os_timer_one_shot(unsigned long long nsecs) +int os_timer_one_shot(int cpu, unsigned long long nsecs) { struct itimerspec its =3D { .it_value.tv_sec =3D nsecs / UM_NSEC_PER_SEC, @@ -71,19 +81,20 @@ int os_timer_one_shot(unsigned long long nsecs) .it_interval.tv_nsec =3D 0, // we cheat here }; =20 - timer_settime(event_high_res_timer, 0, &its, NULL); + timer_settime(event_high_res_timer[cpu], 0, &its, NULL); return 0; } =20 /** * 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; =20 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); } =20 long long os_nsecs(void) --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5DF731DFD9A for ; Mon, 27 Oct 2025 00:18:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524332; cv=none; b=XYxFPN7W9J0KoSACfT9zb1rv4CX1mVmOT1u5BGoDYPxFTk5bT5DVh9r9p9yO9E3t5x9De+e70yct/l8lpDW7F3pbAKW9NXwVRO5DYUD1VtZtRZm2MkEDhCVvvNwpR2ZNRJXcm+5ek/81wI58anOms84t+QtkDww/USTFqUTGg2k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524332; c=relaxed/simple; bh=x+OS4rueoBxQEeQ8MAfIJbfy6n+NhCPLPq7MUXQUPi4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mYfmwrUxCYn/TUWfN73Vx4hYoiNYjsYP/qJ9IWpxs6I8+e+sywv2H+uV7LmPTb8LCKX2xbG5IwMLdZ9AXQevBQafe3IU5POJzJefx6S5lgPU0QyIO2WicX7IOvvfDUBHMn3JC6FMclm8OycgOsHzRq75TULuFcSSPRrXaFia2ks= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Idbgp4iV; arc=none smtp.client-ip=91.218.175.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Idbgp4iV" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524326; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RWabFcD6IZ9yDazrAJoT22dL9BDRirb9QhtLNKXl8EE=; b=Idbgp4iVo+H2+tdi+SIddA7G7QKuuTNOBNxfVp2rob9pFZ/qu4XkNjBdX60n7uRHGsyyTY qf3dm7YBK2+s08aSKbhrHBl0P7H8LPK+CC4R/kmSsEXqS8E1OgLlbRab4ATw5ZbFB+muNC kClYW7tTpDOkwK+CdCnaTfzRMD1PmkM= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 5/8] um: Add initial SMP support Date: Mon, 27 Oct 2025 08:18:12 +0800 Message-Id: <20251027001815.1666872-6-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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. Signed-off-by: Tiwei Bie --- .../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/os.h | 17 ++ arch/um/include/shared/skas/mm_id.h | 5 + arch/um/include/shared/skas/skas.h | 2 + arch/um/include/shared/smp.h | 20 ++ arch/um/kernel/Makefile | 1 + arch/um/kernel/irq.c | 25 ++ arch/um/kernel/process.c | 5 + arch/um/kernel/skas/mmu.c | 33 ++- arch/um/kernel/skas/process.c | 19 +- arch/um/kernel/smp.c | 242 ++++++++++++++++++ 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/process.c | 20 ++ arch/um/os-Linux/signal.c | 31 ++- arch/um/os-Linux/skas/process.c | 39 ++- arch/um/os-Linux/smp.c | 148 +++++++++++ arch/um/os-Linux/start_up.c | 4 + arch/um/os-Linux/time.c | 38 ++- 29 files changed, 766 insertions(+), 48 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 diff --git a/Documentation/features/core/generic-idle-thread/arch-support.t= xt b/Documentation/features/core/generic-idle-thread/arch-support.txt index 0735cb5367b4..425442e31fa2 100644 --- a/Documentation/features/core/generic-idle-thread/arch-support.txt +++ b/Documentation/features/core/generic-idle-thread/arch-support.txt @@ -24,7 +24,7 @@ | s390: | ok | | sh: | ok | | sparc: | ok | - | um: | TODO | + | um: | ok | | x86: | ok | | xtensa: | ok | ----------------------- diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 49781bee7905..aa51e2967569 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -28,6 +28,7 @@ config UML select OF_EARLY_FLATTREE if OF select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES + select GENERIC_SMP_IDLE_THREAD select HAVE_GCC_PLUGINS select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN @@ -81,10 +82,48 @@ config HZ int default 100 =20 -config NR_CPUS +config UML_SUBARCH_SUPPORTS_SMP + bool + +config SMP + bool "Symmetric multi-processing support" + default n + depends on UML_SUBARCH_SUPPORTS_SMP + help + This option enables UML SMP support. + + With this enabled, users can tell UML to start multiple virtual + processors. Each virtual processor is 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 available both within the kernel and + across different processes, but remains limited within threads + of the same process in userspace. + +config NR_CPUS_RANGE_BEGIN int - range 1 1 - default 1 + default 1 if !SMP + default 2 + +config NR_CPUS_RANGE_END + int + default 1 if !SMP + default 64 + +config NR_CPUS_DEFAULT + int + default 1 if !SMP + default 2 + +config NR_CPUS + int "Maximum number of CPUs" if SMP + range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END + default NR_CPUS_DEFAULT =20 source "arch/$(HEADER_ARCH)/um/Kconfig" =20 @@ -260,6 +299,7 @@ source "arch/um/drivers/Kconfig" =20 config ARCH_SUSPEND_POSSIBLE def_bool y + depends on !SMP =20 menu "Power management options" =20 diff --git a/arch/um/include/asm/current.h b/arch/um/include/asm/current.h index 8accc6d6f502..159a29b3d4cc 100644 --- a/arch/um/include/asm/current.h +++ b/arch/um/include/asm/current.h @@ -7,15 +7,16 @@ =20 #ifndef __ASSEMBLER__ =20 +#include + struct task_struct; extern struct task_struct *cpu_tasks[NR_CPUS]; =20 static __always_inline struct task_struct *get_current(void) { - return cpu_tasks[0]; + return cpu_tasks[uml_curr_cpu()]; } =20 - #define current get_current() =20 #endif /* __ASSEMBLER__ */ diff --git a/arch/um/include/asm/hardirq.h b/arch/um/include/asm/hardirq.h index 52e2c36267a9..8de71752a9b8 100644 --- a/arch/um/include/asm/hardirq.h +++ b/arch/um/include/asm/hardirq.h @@ -2,8 +2,30 @@ #ifndef __ASM_UM_HARDIRQ_H #define __ASM_UM_HARDIRQ_H =20 -#include +#include +#include =20 #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 =20 +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 + +static inline void ack_bad_irq(unsigned int irq) +{ + pr_crit("unexpected IRQ trap at vector %02x\n", irq); +} + #endif /* __ASM_UM_HARDIRQ_H */ diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h index 4d0e4239f3cc..07d48738b402 100644 --- a/arch/um/include/asm/mmu.h +++ b/arch/um/include/asm/mmu.h @@ -7,16 +7,26 @@ #define __ARCH_UM_MMU_H =20 #include "linux/types.h" +#include +#include #include =20 typedef struct mm_context { struct mm_id id; + struct mutex turnstile; =20 struct list_head list; =20 /* 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; =20 +#define INIT_MM_CONTEXT(mm) \ + .context =3D { \ + .turnstile =3D __MUTEX_INITIALIZER(mm.context.turnstile), \ + .sync_tlb_lock =3D __SPIN_LOCK_INITIALIZER(mm.context.sync_tlb_lock), \ + } + #endif diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 24fdea6f88c3..91aec3698475 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -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 st= art, unsigned long end) { + guard(spinlock_irqsave)(&mm->context.sync_tlb_lock); + if (!mm->context.sync_tlb_range_to) { mm->context.sync_tlb_range_from =3D start; mm->context.sync_tlb_range_to =3D end; diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h index a8cc1d46ddcb..be1743a6ff3c 100644 --- a/arch/um/include/asm/smp.h +++ b/arch/um/include/asm/smp.h @@ -2,6 +2,19 @@ #ifndef __UM_SMP_H #define __UM_SMP_H =20 -#define hard_smp_processor_id() 0 +#if IS_ENABLED(CONFIG_SMP) + +#include +#include + +#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 */ =20 #endif diff --git a/arch/um/include/linux/smp-internal.h b/arch/um/include/linux/s= mp-internal.h new file mode 100644 index 000000000000..1dbcbc23f9c9 --- /dev/null +++ b/arch/um/include/linux/smp-internal.h @@ -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 */ diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 0ca6e4548671..b26e94292fc1 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -216,6 +216,9 @@ extern int can_drop_memory(void); =20 void os_set_pdeathsig(void); =20 +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))); =20 /* 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); =20 +/* 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 diff --git a/arch/um/include/shared/skas/mm_id.h b/arch/um/include/shared/s= kas/mm_id.h index 4f977ef5dda5..fb96c0bd8222 100644 --- a/arch/um/include/shared/skas/mm_id.h +++ b/arch/um/include/shared/skas/mm_id.h @@ -6,6 +6,8 @@ #ifndef __MM_ID_H #define __MM_ID_H =20 +#include + #define STUB_MAX_FDS 4 =20 struct mm_id { @@ -19,6 +21,9 @@ struct mm_id { int syscall_fd_map[STUB_MAX_FDS]; }; =20 +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); =20 #endif diff --git a/arch/um/include/shared/skas/skas.h b/arch/um/include/shared/sk= as/skas.h index 807514e10538..2237ffedec75 100644 --- a/arch/um/include/shared/skas/skas.h +++ b/arch/um/include/shared/skas/skas.h @@ -15,5 +15,7 @@ extern void handle_syscall(struct uml_pt_regs *regs); extern unsigned long current_stub_stack(void); extern struct mm_id *current_mm_id(void); extern void current_mm_sync(void); +void initial_jmpbuf_lock(void); +void initial_jmpbuf_unlock(void); =20 #endif diff --git a/arch/um/include/shared/smp.h b/arch/um/include/shared/smp.h new file mode 100644 index 000000000000..06e3faa95091 --- /dev/null +++ b/arch/um/include/shared/smp.h @@ -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 */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index b8f4e9281599..be60bc451b3f 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_GPROF) +=3D gprof_syms.o obj-$(CONFIG_OF) +=3D dtb.o obj-$(CONFIG_EARLY_PRINTK) +=3D early_printk.o obj-$(CONFIG_STACKTRACE) +=3D stacktrace.o +obj-$(CONFIG_SMP) +=3D smp.o =20 USER_OBJS :=3D config.o =20 diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index e95f6c5a259d..f4b13f15a9c1 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -22,6 +22,9 @@ #include #include =20 +DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); + +#define irq_stats(x) (&per_cpu(irq_stat, x)) =20 /* 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_s= i, { 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; +} diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index a60230b299da..3953e2f2d9a7 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -216,6 +216,11 @@ void arch_cpu_idle(void) um_idle_sleep(); } =20 +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? */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index afe9a2f251ef..00957788591b 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -23,17 +23,36 @@ static_assert(sizeof(struct stub_data) =3D=3D STUB_DATA= _PAGES * UM_KERN_PAGE_SIZE); static spinlock_t mm_list_lock; static struct list_head mm_list; =20 +void enter_turnstile(struct mm_id *mm_id) __acquires(turnstile) +{ + struct mm_context *ctx =3D 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 =3D 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 =3D &mm->context.id; unsigned long stack =3D 0; int ret =3D -ENOMEM; =20 + mutex_init(&mm->context.turnstile); + spin_lock_init(&mm->context.sync_tlb_lock); + stack =3D __get_free_pages(GFP_KERNEL | __GFP_ZERO, ilog2(STUB_DATA_PAGES= )); if (stack =3D=3D 0) goto out; =20 new_id->stack =3D stack; + new_id->syscall_data_len =3D 0; + new_id->syscall_fd_num =3D 0; =20 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; } =20 + 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 =3D -1; @@ -82,10 +104,6 @@ void destroy_context(struct mm_struct *mm) os_close_file(mmu->id.sock); =20 free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES)); - - guard(spinlock_irqsave)(&mm_list_lock); - - list_del(&mm->context.list); } =20 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 =3D -1; =20 - /* - * NOTE: If SMP is implemented, a futex_wake - * needs to be added here. - */ stub_data =3D (void *)mm_context->id.stack; stub_data->futex =3D FUTEX_IN_KERN; +#if IS_ENABLED(CONFIG_SMP) + os_futex_wake(&stub_data->futex); +#endif =20 /* * NOTE: Currently executing syscalls by diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 5881b17eb987..4a7673b0261a 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -7,6 +7,7 @@ #include #include #include +#include =20 #include =20 @@ -26,12 +27,12 @@ static int __init start_kernel_proc(void *unused) return 0; } =20 -static char cpu0_irqstack[THREAD_SIZE] __aligned(THREAD_SIZE); +char cpu_irqstacks[NR_CPUS][THREAD_SIZE] __aligned(THREAD_SIZE); =20 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); =20 init_new_thread_signals(); =20 @@ -64,3 +65,15 @@ void current_mm_sync(void) =20 um_tlb_sync(current->mm); } + +static DEFINE_SPINLOCK(initial_jmpbuf_spinlock); + +void initial_jmpbuf_lock(void) +{ + spin_lock_irq(&initial_jmpbuf_spinlock); +} + +void initial_jmpbuf_unlock(void) +{ + spin_unlock_irq(&initial_jmpbuf_spinlock); +} diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c new file mode 100644 index 000000000000..f1e52b7348fb --- /dev/null +++ b/arch/um/kernel/smp.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Ant Group + * Author: Tiwei Bie + * + * Based on the previous implementation in TT mode + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + UML_IPI_RES =3D 0, + UML_IPI_CALL_SINGLE, + UML_IPI_CALL, + UML_IPI_STOP, +}; + +void arch_smp_send_reschedule(int cpu) +{ + os_send_ipi(cpu, UML_IPI_RES); +} + +void arch_send_call_function_single_ipi(int cpu) +{ + os_send_ipi(cpu, UML_IPI_CALL_SINGLE); +} + +void arch_send_call_function_ipi_mask(const struct cpumask *mask) +{ + int cpu; + + for_each_cpu(cpu, mask) + os_send_ipi(cpu, UML_IPI_CALL); +} + +void smp_send_stop(void) +{ + int cpu, me =3D smp_processor_id(); + + for_each_online_cpu(cpu) { + if (cpu =3D=3D me) + continue; + os_send_ipi(cpu, UML_IPI_STOP); + } +} + +static void ipi_handler(int vector, struct uml_pt_regs *regs) +{ + struct pt_regs *old_regs =3D set_irq_regs((struct pt_regs *)regs); + int cpu =3D raw_smp_processor_id(); + + irq_enter(); + + if (current->mm) + os_alarm_process(current->mm->context.id.pid); + + switch (vector) { + case UML_IPI_RES: + inc_irq_stat(irq_resched_count); + scheduler_ipi(); + break; + + case UML_IPI_CALL_SINGLE: + inc_irq_stat(irq_call_count); + generic_smp_call_function_single_interrupt(); + break; + + case UML_IPI_CALL: + inc_irq_stat(irq_call_count); + generic_smp_call_function_interrupt(); + break; + + case UML_IPI_STOP: + set_cpu_online(cpu, false); + while (1) + pause(); + break; + + default: + pr_err("CPU#%d received unknown IPI (vector=3D%d)!\n", cpu, vector); + break; + } + + irq_exit(); + set_irq_regs(old_regs); +} + +void uml_ipi_handler(int vector) +{ + struct uml_pt_regs r =3D { .is_user =3D 0 }; + + preempt_disable(); + ipi_handler(vector, &r); + preempt_enable(); +} + +/* AP states used only during CPU startup */ +enum { + UML_CPU_PAUSED =3D 0, + UML_CPU_RUNNING, +}; + +static int cpu_states[NR_CPUS]; + +static int start_secondary(void *unused) +{ + int err, cpu =3D raw_smp_processor_id(); + + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); + + err =3D um_setup_timer(); + if (err) + panic("CPU#%d failed to setup timer, err =3D %d", cpu, err); + + local_irq_enable(); + + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); + + return 0; +} + +void uml_start_secondary(void *opaque) +{ + int cpu =3D raw_smp_processor_id(); + struct mm_struct *mm =3D &init_mm; + struct task_struct *idle; + + stack_protections((unsigned long) &cpu_irqstacks[cpu]); + set_sigstack(&cpu_irqstacks[cpu], THREAD_SIZE); + + set_cpu_present(cpu, true); + os_futex_wait(&cpu_states[cpu], UML_CPU_PAUSED); + + smp_rmb(); /* paired with smp_wmb() in __cpu_up() */ + + idle =3D cpu_tasks[cpu]; + idle->thread_info.cpu =3D cpu; + + mmgrab(mm); + idle->active_mm =3D mm; + + idle->thread.request.thread.proc =3D start_secondary; + idle->thread.request.thread.arg =3D NULL; + + new_thread(task_stack_page(idle), &idle->thread.switch_buf, + new_thread_handler); + os_start_secondary(opaque, &idle->thread.switch_buf); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + int err, cpu, me =3D smp_processor_id(); + unsigned long deadline; + + os_init_smp(); + + for_each_possible_cpu(cpu) { + if (cpu =3D=3D me) + continue; + + pr_debug("Booting processor %d...\n", cpu); + err =3D os_start_cpu_thread(cpu); + if (err) { + pr_crit("CPU#%d failed to start cpu thread, err =3D %d", + cpu, err); + continue; + } + + deadline =3D jiffies + msecs_to_jiffies(1000); + spin_until_cond(cpu_present(cpu) || + time_is_before_jiffies(deadline)); + + if (!cpu_present(cpu)) + pr_crit("CPU#%d failed to boot\n", cpu); + } +} + +int __cpu_up(unsigned int cpu, struct task_struct *tidle) +{ + cpu_tasks[cpu] =3D tidle; + smp_wmb(); /* paired with smp_rmb() in uml_start_secondary() */ + cpu_states[cpu] =3D UML_CPU_RUNNING; + os_futex_wake(&cpu_states[cpu]); + spin_until_cond(cpu_online(cpu)); + + return 0; +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ +} + +/* Set in uml_ncpus_setup */ +int uml_ncpus =3D 1; + +void __init prefill_possible_map(void) +{ + int cpu; + + for (cpu =3D 0; cpu < uml_ncpus; cpu++) + set_cpu_possible(cpu, true); + for (; cpu < NR_CPUS; cpu++) + set_cpu_possible(cpu, false); +} + +static int __init uml_ncpus_setup(char *line, int *add) +{ + *add =3D 0; + + if (kstrtoint(line, 10, ¨_ncpus)) { + os_warn("%s: Couldn't parse '%s'\n", __func__, line); + return -1; + } + + uml_ncpus =3D clamp(uml_ncpus, 1, NR_CPUS); + + return 0; +} + +__uml_setup("ncpus=3D", uml_ncpus_setup, +"ncpus=3D<# of desired CPUs>\n" +" This tells UML how many virtual processors to start. The maximum\n" +" number of supported virtual processors can be obtained by querying\n" +" the CONFIG_NR_CPUS option using --showconfig.\n\n" +); + +EXPORT_SYMBOL(uml_curr_cpu); diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index cf7e0d4407f2..39608cccf2c6 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -162,9 +162,11 @@ int um_tlb_sync(struct mm_struct *mm) { pgd_t *pgd; struct vm_ops ops; - unsigned long addr =3D mm->context.sync_tlb_range_from, next; + unsigned long addr, next; int ret =3D 0; =20 + guard(spinlock_irqsave)(&mm->context.sync_tlb_lock); + if (mm->context.sync_tlb_range_to =3D=3D 0) return 0; =20 @@ -177,6 +179,7 @@ int um_tlb_sync(struct mm_struct *mm) ops.unmap =3D unmap; } =20 + addr =3D mm->context.sync_tlb_range_from; pgd =3D pgd_offset(mm, addr); do { next =3D pgd_addr_end(addr, mm->context.sync_tlb_range_to); diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 5b80a3a89c20..177615820a4c 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -316,7 +316,7 @@ unsigned long segv(struct faultinfo fi, unsigned long i= p, int is_user, if (!is_user && regs) current->thread.segv_regs =3D container_of(regs, struct pt_regs, regs); =20 - if (!is_user && init_mm.context.sync_tlb_range_to) { + if (!is_user && address >=3D 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 diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index cfbbbf8500c3..a6890e908a5d 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -19,6 +19,7 @@ #include #include #include +#include =20 #include #include @@ -71,6 +72,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) { int i =3D 0; =20 +#if IS_ENABLED(CONFIG_SMP) + i =3D (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); =20 - return 0; } =20 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; } =20 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 =3D command_line; setup_hostinfo(host_info, sizeof host_info); + prefill_possible_map(); =20 if (os_getrandom(rng_seed, sizeof(rng_seed), 0) =3D=3D sizeof(rng_seed)) { add_bootloader_randomness(rng_seed, sizeof(rng_seed)); @@ -455,6 +464,18 @@ void apply_alternatives(struct alt_instr *start, struc= t alt_instr *end) { } =20 +#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) { /* diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index fae836713487..70c73c22f715 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -16,8 +16,10 @@ CFLAGS_main.o +=3D -Wno-frame-larger-than =20 obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) +=3D elf_aux.o =20 +obj-$(CONFIG_SMP) +=3D smp.o + USER_OBJS :=3D $(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 =20 include $(srctree)/arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h index c2c7a0dc673c..bac9fcc8c14c 100644 --- a/arch/um/os-Linux/internal.h +++ b/arch/um/os-Linux/internal.h @@ -4,6 +4,7 @@ =20 #include #include +#include =20 /* * elf_aux.c @@ -18,6 +19,7 @@ void check_tmpexec(void); /* * signal.c */ +extern __thread int signals_enabled; int timer_alarm_pending(void); =20 /* @@ -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_si= gsys); + +/* + * smp.c + */ +#define IPI_SIGNAL SIGRTMIN + #endif /* __UM_OS_LINUX_INTERNAL_H */ diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 00b49e90d05f..3a2a84ab9325 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -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 =3D 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 =3D syscall(__NR_futex, uaddr, FUTEX_WAKE, INT_MAX, + NULL, NULL, 0)); + return r < 0 ? -errno : r; +} diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 554a87dd32cc..327fb3c52fc7 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -69,7 +69,7 @@ static void sig_handler_common(int sig, struct siginfo *s= i, mcontext_t *mc) #define SIGCHLD_BIT 2 #define SIGCHLD_MASK (1 << SIGCHLD_BIT) =20 -static __thread int signals_enabled; +__thread int 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; } =20 -void block_signals(void) +static inline void __block_signals(void) { + if (!signals_enabled) + return; + + os_local_ipi_disable(); + barrier(); signals_enabled =3D 0; +} + +static inline void __unblock_signals(void) +{ + if (signals_enabled) + return; + + signals_enabled =3D 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 =3D=3D 1) return; =20 - signals_enabled =3D 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 =3D 0; + __block_signals(); um_trace_signals_off(); =20 /* @@ -344,7 +365,7 @@ void unblock_signals(void) =20 /* Re-enable signals and trace that we're doing so. */ um_trace_signals_on(); - signals_enabled =3D 1; + __unblock_signals(); } } =20 diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/proces= s.c index 0bc10cd4cbed..2b06d400381e 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -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; =20 @@ -563,6 +563,13 @@ void userspace(struct uml_pt_regs *regs) while (1) { struct mm_id *mm_id =3D current_mm_id(); =20 + /* + * 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) } =20 if (proc_data->si_offset > sizeof(proc_data->sigstack) - sizeof(*si)) - panic("%s - Invalid siginfo offset from child", - __func__); - si =3D (void *)&proc_data->sigstack[proc_data->si_offset]; + panic("%s - Invalid siginfo offset from child", __func__); + + si =3D &si_local; + memcpy(si, &proc_data->sigstack[proc_data->si_offset], sizeof(*si)); =20 regs->is_user =3D 1; =20 @@ -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 =3D &si_ptrace; + (struct siginfo *)&si_local); + si =3D &si_local; break; default: si =3D NULL; @@ -740,6 +748,8 @@ void userspace(struct uml_pt_regs *regs) } } =20 + exit_turnstile(mm_id); + UPT_SYSCALL_NR(regs) =3D -1; /* Assume: It's not a syscall */ =20 if (sig) { @@ -809,10 +819,9 @@ void switch_threads(jmp_buf *me, jmp_buf *you) =20 static jmp_buf initial_jmpbuf; =20 -/* XXX Make these percpu */ -static void (*cb_proc)(void *arg); -static void *cb_arg; -static jmp_buf *cb_back; +static __thread void (*cb_proc)(void *arg); +static __thread void *cb_arg; +static __thread jmp_buf *cb_back; =20 int start_idle_thread(void *stack, jmp_buf *switch_buf) { @@ -866,10 +875,10 @@ void initial_thread_cb_skas(void (*proc)(void *), voi= d *arg) cb_arg =3D arg; cb_back =3D &here; =20 - block_signals_trace(); + initial_jmpbuf_lock(); if (UML_SETJMP(&here) =3D=3D 0) UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); - unblock_signals_trace(); + initial_jmpbuf_unlock(); =20 cb_proc =3D NULL; cb_arg =3D NULL; @@ -878,8 +887,9 @@ void initial_thread_cb_skas(void (*proc)(void *), void = *arg) =20 void halt_skas(void) { - block_signals_trace(); + initial_jmpbuf_lock(); UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT); + /* unreachable */ } =20 static bool noreboot; @@ -899,6 +909,7 @@ __uml_setup("noreboot", noreboot_cmd_param, =20 void reboot_skas(void) { - block_signals_trace(); + initial_jmpbuf_lock(); UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT); + /* unreachable */ } diff --git a/arch/um/os-Linux/smp.c b/arch/um/os-Linux/smp.c new file mode 100644 index 000000000000..18d3858a7cd2 --- /dev/null +++ b/arch/um/os-Linux/smp.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Ant Group + * Author: Tiwei Bie + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +struct cpu_thread_data { + int cpu; + sigset_t sigset; +}; + +static __thread int __curr_cpu; + +int uml_curr_cpu(void) +{ + return __curr_cpu; +} + +static pthread_t cpu_threads[CONFIG_NR_CPUS]; + +static void *cpu_thread(void *arg) +{ + struct cpu_thread_data *data =3D arg; + + __curr_cpu =3D data->cpu; + + uml_start_secondary(data); + + return NULL; +} + +int os_start_cpu_thread(int cpu) +{ + struct cpu_thread_data *data; + sigset_t sigset, oset; + int err; + + data =3D uml_kmalloc(sizeof(*data), UM_GFP_ATOMIC); + if (!data) + return -ENOMEM; + + sigfillset(&sigset); + if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) { + err =3D errno; + goto err; + } + + data->cpu =3D cpu; + data->sigset =3D oset; + + err =3D pthread_create(&cpu_threads[cpu], NULL, cpu_thread, data); + if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) + panic("Failed to restore the signal mask, errno =3D %d", errno); + if (err !=3D 0) + goto err; + + return 0; + +err: + kfree(data); + return -err; +} + +void os_start_secondary(void *arg, jmp_buf *switch_buf) +{ + struct cpu_thread_data *data =3D arg; + + sigaddset(&data->sigset, IPI_SIGNAL); + sigaddset(&data->sigset, SIGIO); + + if (sigprocmask(SIG_SETMASK, &data->sigset, NULL) < 0) + panic("Failed to restore the signal mask, errno =3D %d", errno); + + kfree(data); + longjmp(*switch_buf, 1); + + /* unreachable */ + printk(UM_KERN_ERR "impossible long jump!"); + fatal_sigsegv(); +} + +int os_send_ipi(int cpu, int vector) +{ + union sigval value =3D { .sival_int =3D vector }; + + return pthread_sigqueue(cpu_threads[cpu], IPI_SIGNAL, value); +} + +static void __local_ipi_set(int enable) +{ + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, IPI_SIGNAL); + + if (sigprocmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) + panic("%s: sigprocmask failed, errno =3D %d", __func__, errno); +} + +void os_local_ipi_enable(void) +{ + __local_ipi_set(1); +} + +void os_local_ipi_disable(void) +{ + __local_ipi_set(0); +} + +static void ipi_sig_handler(int sig, siginfo_t *si, void *uc) +{ + int save_errno =3D errno; + + signals_enabled =3D 0; + um_trace_signals_off(); + + uml_ipi_handler(si->si_value.sival_int); + + um_trace_signals_on(); + signals_enabled =3D 1; + + errno =3D save_errno; +} + +void __init os_init_smp(void) +{ + struct sigaction action =3D { + .sa_sigaction =3D ipi_sig_handler, + .sa_flags =3D SA_SIGINFO | SA_ONSTACK | SA_RESTART, + }; + + sigfillset(&action.sa_mask); + + if (sigaction(IPI_SIGNAL, &action, NULL) < 0) + panic("%s: sigaction failed, errno =3D %d", __func__, errno); + + cpu_threads[0] =3D pthread_self(); +} diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index a827c2e01aa5..61c61e9c246c 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -481,6 +482,9 @@ void __init os_early_checks(void) fatal("SECCOMP userspace requested but not functional!\n"); } =20 + if (uml_ncpus > 1) + fatal("SMP is not supported with PTRACE userspace.\n"); + using_seccomp =3D 0; check_ptrace(); =20 diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index e0197bfe4ac9..13ebc86918d4 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -11,9 +11,11 @@ #include #include #include +#include #include #include #include +#include #include #include "internal.h" =20 @@ -41,7 +43,8 @@ long long os_persistent_clock_emulation(void) */ int os_timer_create(void) { - timer_t *t =3D &event_high_res_timer[0]; + int cpu =3D uml_curr_cpu(); + timer_t *t =3D &event_high_res_timer[cpu]; struct sigevent sev =3D { .sigev_notify =3D SIGEV_THREAD_ID, .sigev_signo =3D SIGALRM, @@ -105,24 +108,49 @@ long long os_nsecs(void) return timespec_to_ns(&ts); } =20 +static __thread int 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 =3D signalfd(-1, &set, SFD_CLOEXEC); + if (wake_signals < 0) + panic("Failed to create signal FD, errno =3D %d", errno); +} + /** * os_idle_sleep() - sleep until interrupted */ void os_idle_sleep(void) { - sigset_t set, old; + sigset_t set; =20 - /* 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); =20 /* * 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); =20 /* Restore the signal mask. */ sigprocmask(SIG_UNBLOCK, &set, NULL); --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-186.mta0.migadu.com (out-186.mta0.migadu.com [91.218.175.186]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38C2D21D00A for ; Mon, 27 Oct 2025 00:18:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.186 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524334; cv=none; b=POI7gncXpqx5ANg7xFWEWkmnRAZ1Q6geH8PRkrG12D4UJh58s/xEcvmdE2rhyuT18ngL6dCz/w8KfXSLRexdACO99gM2d4RAz5a2XzkRkpwdWPBYrxXII/ZqT/2qK9uJDgL+hmbTdGu8xI5Ec16fpcp49ppAgpaVvwMU87oHM30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524334; c=relaxed/simple; bh=3BGzPF/5VpNXrRT172DmrvHLqGBDLyHCCXwQhR82DVQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kvM+Ses/wHmHTOGEdioK+X0UHBOv4AtEBb7gIXySoVJuJYymNIZ2iIV++tq1PqJSInnm6MfbZz5AvdR5JKCinf+jPoIiHf2bXcid15G86sqk5w0B+16sJo1RknEo8xExCqmtq3lFMJ/Sn2n985rMQrN/UXnE2DhCpJJAKcvKlvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=eOZuMP3Y; arc=none smtp.client-ip=91.218.175.186 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="eOZuMP3Y" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524329; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bl37ymUxPOSh0uADw//c0j6dKMZwyMMccmkvzyDx4iM=; b=eOZuMP3YnOEWGFWVtF/ftO+8SRUHWmHScyHnXOlOguZMARhIFfjX6sqmO47lRG+itvrsHM VJbcALMJ2V6BS3ViFqh6zBNwGFDtmBMcmAwdyTK1+X8+MWv4ww2WP3ptm+SvR80zQMPiss GaKUK0KelWKyr+AlBBknSDXoK/f99HM= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev, Johannes Berg Subject: [PATCH v4 6/8] um: vdso: Remove getcpu support on x86 Date: Mon, 27 Oct 2025 08:18:13 +0800 Message-Id: <20251027001815.1666872-7-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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. Suggested-by: Johannes Berg Signed-off-by: Tiwei Bie --- arch/x86/um/vdso/um_vdso.c | 20 -------------------- arch/x86/um/vdso/vdso.lds.S | 2 -- 2 files changed, 22 deletions(-) diff --git a/arch/x86/um/vdso/um_vdso.c b/arch/x86/um/vdso/um_vdso.c index cbae2584124f..43a5ffcc7158 100644 --- a/arch/x86/um/vdso/um_vdso.c +++ b/arch/x86/um/vdso/um_vdso.c @@ -10,14 +10,12 @@ #define DISABLE_BRANCH_PROFILING =20 #include -#include #include =20 /* 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_ca= che *unused); =20 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, alia= s("__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 =3D 0; - if (node) - *node =3D 0; - - return 0; -} - -long getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *tc= ache) - __attribute__((weak, alias("__vdso_getcpu"))); diff --git a/arch/x86/um/vdso/vdso.lds.S b/arch/x86/um/vdso/vdso.lds.S index 73c508587a98..401600effc0a 100644 --- a/arch/x86/um/vdso/vdso.lds.S +++ b/arch/x86/um/vdso/vdso.lds.S @@ -22,8 +22,6 @@ VERSION { __vdso_clock_gettime; gettimeofday; __vdso_gettimeofday; - getcpu; - __vdso_getcpu; time; __vdso_time; local: *; --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-183.mta0.migadu.com (out-183.mta0.migadu.com [91.218.175.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 309D4211A14 for ; Mon, 27 Oct 2025 00:18:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.183 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524335; cv=none; b=QjyJElQYS2p3jUsS3CrJBw9iTZLSEqf7T+Ks+sFGWd78oBFbzaubm4O1DdwVZonWtSodZlvDxCRvFb+MO4cxwhyHOzxW6SMvJryc6y4ElkloMBKnnMHD5l/MnlMNJpKH3asb6q057fy0HjDGEGwGqefnFxPZZUkYqyoS9zgM8ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524335; c=relaxed/simple; bh=9DoCjxBOtuHLpHgIlbx76kr9AICQ+StOVxBkqP6vrGA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Zy6NQGLjeo4khq6PphbL0BhIaq+Z1mRnVbTpUtVkfCFLv34xXeOVd8C43q/FMDu3hqKzkAjDd2h8ang/qimbWmPZWMy0GyH6MrZQHW1oXP23R1/GhAOfRAoyK3/og+COV95yahoFlDIdFSwhGtfrec/waWKOFETbpdM9FMSF0rc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=T4PKl5X+; arc=none smtp.client-ip=91.218.175.183 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="T4PKl5X+" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524332; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Qv8GrhWWLvpi+yXjcVXvopwH0zWKk+Fo+xAzYv1qf0M=; b=T4PKl5X+6V424JgZsHbjgohHFQmgP76ww0hRCuAU8l0OHdP80gOU4h5zkGhwT54VMt6IiR g/0xY78vvtuBWUgD/WDWefBPq53HQnlB1K8Xq7XZZgmL5nsY2iJjmGFPmkGGV8PZPjd2t3 CQmBS+q7pZDeiog2t+/nDV+DmIglumA= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev, linux-arch@vger.kernel.org Subject: [PATCH v4 7/8] asm-generic: percpu: Add assembly guard Date: Mon, 27 Oct 2025 08:18:14 +0800 Message-Id: <20251027001815.1666872-8-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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. Cc: Arnd Bergmann Cc: linux-arch@vger.kernel.org Signed-off-by: Tiwei Bie Acked-by: Arnd Bergmann --- include/asm-generic/percpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 02aeca21479a..6628670bcb90 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -2,6 +2,8 @@ #ifndef _ASM_GENERIC_PERCPU_H_ #define _ASM_GENERIC_PERCPU_H_ =20 +#ifndef __ASSEMBLER__ + #include #include #include @@ -557,4 +559,5 @@ do { \ this_cpu_generic_cmpxchg(pcp, oval, nval) #endif =20 +#endif /* __ASSEMBLER__ */ #endif /* _ASM_GENERIC_PERCPU_H_ */ --=20 2.34.1 From nobody Thu Dec 18 19:59:05 2025 Received: from out-180.mta0.migadu.com (out-180.mta0.migadu.com [91.218.175.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E8ABF224AF7 for ; Mon, 27 Oct 2025 00:18:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524338; cv=none; b=pwDeFruPf4pbE7q8gh6ds7Lj1BzvM1jhHPCraV1i9/P/BiCb0a8iNu0tx+Imkp5/KMFmdFyyYviDw/OjkcMogWQ9qJcMdESq2kh1R84bUd8LBAlUNvSbC+BGI14Ul6vj7X4lI+WZ790kL6Wr9VLKEbaXB4Jc2nuv08C0ngyMgLc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761524338; c=relaxed/simple; bh=gQC8pzFStzV9HCUhKstI64TzErxvRdTVTp4p2D5OXC0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AJj67nd/gqOZ37rPHLDoRe/IWPTWDAJJLR1oeNrJB6pjkrzAb7BX11hzI2Z/pwTEB2aY9mV4PiUOdvT6nsShnbP2Vp0of/FY5ZZ7fUZOFq0hbI1nkAczXWxkSs6CVFeJESxHxMyuE/mucx7djOqwauhvMQ0IYia2KsL/KWJC1aI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=RPgmt2Zq; arc=none smtp.client-ip=91.218.175.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="RPgmt2Zq" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1761524334; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5PrMNLYQkZylc5n1vPcSLoxov+KMpq+EjdZMAgd4fn0=; b=RPgmt2Zq6/tx29vMni0i4vk0rs03J2goYZRIH8kXNfJhbpqasu7y1B0zMn8hKwCXEPeRP2 qwDRg3vvxoovXEYMOlt9+n+Z0yig9GffQJYFsm/34VSXyt2CPF9HjxN5bm4nQXrTs1vluh LWujaIofUYT619yAVrtIlDeTgGBqcJw= From: Tiwei Bie To: richard@nod.at, anton.ivanov@cambridgegreys.com, johannes@sipsolutions.net Cc: linux-um@lists.infradead.org, linux-kernel@vger.kernel.org, benjamin@sipsolutions.net, arnd@arndb.de, tiwei.btw@antgroup.com, tiwei.bie@linux.dev Subject: [PATCH v4 8/8] um: Enable SMP support on x86 Date: Mon, 27 Oct 2025 08:18:15 +0800 Message-Id: <20251027001815.1666872-9-tiwei.bie@linux.dev> In-Reply-To: <20251027001815.1666872-1-tiwei.bie@linux.dev> References: <20251027001815.1666872-1-tiwei.bie@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Tiwei Bie 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/20250515085708.2510123-1-mingo@kernel.org/ Signed-off-by: Tiwei Bie --- 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 diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 986045d5e638..c52fb5cb8d21 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig @@ -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 =20 config 64BIT bool "64-bit kernel" if "$(SUBARCH)" =3D "x86" diff --git a/arch/x86/um/asm/spinlock.h b/arch/x86/um/asm/spinlock.h new file mode 100644 index 000000000000..20fc77514214 --- /dev/null +++ b/arch/x86/um/asm/spinlock.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_UM_SPINLOCK_H +#define __ASM_UM_SPINLOCK_H + +#include +#include + +#endif /* __ASM_UM_SPINLOCK_H */ --=20 2.34.1