* [RFC PATCH 0/9] simplified UML/NOMMU approach
@ 2026-07-20 18:26 Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 1/9] x86/um: nommu: elf loader for fdpic Johannes Berg
` (9 more replies)
0 siblings, 10 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
Hi,
After Hajime's talk at netdevconf 0x1A I was this time really
tempted into implementing an approach to NOMMU UML that I'd
thought about quite a while ago, and here's the resulting
code. I had prototyped some of this with LLM help, but now
have pretty much reworked most of it (except boilerplate).
Instead of using a wholly new architectural interface, new
process/thread handling, new seccomp machinery etc. this
just reuses all the existing infrastructure (we're not in
fact trying to run UML on nommu, but run _as_ nommu), but
makes runner processes for each CPU instead of each userspace
MM (as it would be on MMU).
This eventually results in a far simpler implementation that
doesn't have all the complexity of the syscall handling yet
again.
It's also more capable:
- continues working with ptrace
- doesn't require disabling SMP
(just has a runner per CPU)
- should work on 32-bit (untested)
- keeps physmem FD, which in theory should allow virtio
PCI devices, but PCI doesn't build on !MMU right now
However, it does go in an entirely different direction
and while it doesn't entirely close off all things for
optimisations wrt. syscall speed that the much older
versions of the NOMMU patchset did, it does create the
infrastructure in a way that doesn't make that easier.
Personally, I think the only real use case for this
whole thing is NOMMU testing (which was requested), and
we don't really need everything else.
Note: the futex thing seems odd. I mirrored the existing
implementation, but I think it's just wrong. There's a
FIXME in the code for now.
It does boot ghcr.io/thehajime/alpine:3.20.3-um-nommu
as was documented before.
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFC PATCH 1/9] x86/um: nommu: elf loader for fdpic
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 2/9] um: decouple MMU specific code from the common part Johannes Berg
` (8 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki, Kees Cook
From: Hajime Tazaki <thehajime@gmail.com>
As UML supports CONFIG_MMU=n case, it has to use an alternate ELF
loader, FDPIC ELF loader. In this commit, we added necessary
definitions in the arch, as UML has not been used so far. It also
updates Kconfig file to use BINFMT_ELF_FDPIC under !MMU environment.
Acked-by: Kees Cook <kees@kernel.org>
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Link: https://patch.msgid.link/fa22ec46b0d78df65a005d4a33d05edebbbd381d.1770170302.git.thehajime@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/include/asm/mmu.h | 5 +++++
arch/um/include/asm/ptrace-generic.h | 6 ++++++
arch/x86/um/asm/elf.h | 8 ++++++--
fs/Kconfig.binfmt | 2 +-
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h
index 07d48738b402..82a919132aff 100644
--- a/arch/um/include/asm/mmu.h
+++ b/arch/um/include/asm/mmu.h
@@ -21,6 +21,11 @@ typedef struct mm_context {
spinlock_t sync_tlb_lock;
unsigned long sync_tlb_range_from;
unsigned long sync_tlb_range_to;
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ unsigned long exec_fdpic_loadmap;
+ unsigned long interp_fdpic_loadmap;
+#endif
} mm_context_t;
#define INIT_MM_CONTEXT(mm) \
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h
index 86d74f9d33cf..62e9916078ec 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -29,6 +29,12 @@ struct pt_regs {
#define PTRACE_OLDSETOPTIONS 21
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+#define PTRACE_GETFDPIC 31
+#define PTRACE_GETFDPIC_EXEC 0
+#define PTRACE_GETFDPIC_INTERP 1
+#endif
+
struct task_struct;
extern long subarch_ptrace(struct task_struct *child, long request,
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index 22d0111b543b..388fe669886c 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -9,6 +9,7 @@
#include <skas.h>
#define CORE_DUMP_USE_REGSET
+#define ELF_FDPIC_CORE_EFLAGS 0
#ifdef CONFIG_X86_32
@@ -158,8 +159,11 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
extern unsigned long um_vdso_addr;
#define AT_SYSINFO_EHDR 33
-#define ARCH_DLINFO NEW_AUX_ENT(AT_SYSINFO_EHDR, um_vdso_addr)
-
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, um_vdso_addr); \
+ NEW_AUX_ENT(AT_MINSIGSTKSZ, 0); \
+} while (0)
#endif
typedef unsigned long elf_greg_t;
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 1949e25c7741..0a92bebd5f75 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -58,7 +58,7 @@ config ARCH_USE_GNU_PROPERTY
config BINFMT_ELF_FDPIC
bool "Kernel support for FDPIC ELF binaries"
default y if !BINFMT_ELF
- depends on ARM || ((M68K || RISCV || SUPERH || XTENSA) && !MMU)
+ depends on ARM || ((M68K || RISCV || SUPERH || UML || XTENSA) && !MMU)
select ELFCORE
help
ELF FDPIC binaries are based on ELF, but allow the individual load
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 2/9] um: decouple MMU specific code from the common part
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 1/9] x86/um: nommu: elf loader for fdpic Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 3/9] um: nommu: memory handling Johannes Berg
` (7 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
From: Hajime Tazaki <thehajime@gmail.com>
This splits the memory, process related code with common and MMU
specific parts in order to avoid ifdefs in .c file and duplication
between MMU and !MMU.
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Link: https://patch.msgid.link/e789a6ce3204b7697adba6d70e52e1ec3b61a451.1770170302.git.thehajime@gmail.com
[drop many unnecessary changes]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/kernel/Makefile | 3 +-
arch/um/kernel/mem-pgtable.c | 55 ++++++++++++++++++++++++++++++++++++
arch/um/kernel/mem.c | 35 -----------------------
3 files changed, 57 insertions(+), 36 deletions(-)
create mode 100644 arch/um/kernel/mem-pgtable.c
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index be60bc451b3f..d56fe6d829cc 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -16,9 +16,10 @@ always-$(KBUILD_BUILTIN) := vmlinux.lds
obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
physmem.o process.o ptrace.o reboot.o sigio.o \
- signal.o sysrq.o time.o tlb.o trap.o \
+ signal.o sysrq.o time.o trap.o \
um_arch.o umid.o kmsg_dump.o capflags.o skas/
obj-y += load_file.o
+obj-$(CONFIG_MMU) += mem-pgtable.o tlb.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
diff --git a/arch/um/kernel/mem-pgtable.c b/arch/um/kernel/mem-pgtable.c
new file mode 100644
index 000000000000..549da1d3bff0
--- /dev/null
+++ b/arch/um/kernel/mem-pgtable.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ */
+
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/memblock.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <as-layout.h>
+#include <init.h>
+#include <kern.h>
+#include <kern_util.h>
+#include <mem_user.h>
+#include <os.h>
+#include <um_malloc.h>
+
+
+/* Allocate and free page tables. */
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+ if (pgd) {
+ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+ return pgd;
+}
+
+static const pgprot_t protection_map[16] = {
+ [VM_NONE] = PAGE_NONE,
+ [VM_READ] = PAGE_READONLY,
+ [VM_WRITE] = PAGE_COPY,
+ [VM_WRITE | VM_READ] = PAGE_COPY,
+ [VM_EXEC] = PAGE_READONLY,
+ [VM_EXEC | VM_READ] = PAGE_READONLY,
+ [VM_EXEC | VM_WRITE] = PAGE_COPY,
+ [VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY,
+ [VM_SHARED] = PAGE_NONE,
+ [VM_SHARED | VM_READ] = PAGE_READONLY,
+ [VM_SHARED | VM_WRITE] = PAGE_SHARED,
+ [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED,
+ [VM_SHARED | VM_EXEC] = PAGE_READONLY,
+ [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READONLY,
+ [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED,
+ [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED
+};
+DECLARE_VM_GET_PAGE_PROT
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 1eef0e42ef5d..4b84760b5e55 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -6,7 +6,6 @@
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/memblock.h>
-#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -91,45 +90,11 @@ void free_initmem(void)
{
}
-/* Allocate and free page tables. */
-
-pgd_t *pgd_alloc(struct mm_struct *mm)
-{
- pgd_t *pgd = __pgd_alloc(mm, 0);
-
- if (pgd)
- memcpy(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-
- return pgd;
-}
-
void *uml_kmalloc(int size, int flags)
{
return kmalloc(size, flags);
}
-static const pgprot_t protection_map[16] = {
- [VM_NONE] = PAGE_NONE,
- [VM_READ] = PAGE_READONLY,
- [VM_WRITE] = PAGE_COPY,
- [VM_WRITE | VM_READ] = PAGE_COPY,
- [VM_EXEC] = PAGE_READONLY,
- [VM_EXEC | VM_READ] = PAGE_READONLY,
- [VM_EXEC | VM_WRITE] = PAGE_COPY,
- [VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY,
- [VM_SHARED] = PAGE_NONE,
- [VM_SHARED | VM_READ] = PAGE_READONLY,
- [VM_SHARED | VM_WRITE] = PAGE_SHARED,
- [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED,
- [VM_SHARED | VM_EXEC] = PAGE_READONLY,
- [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READONLY,
- [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED,
- [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED
-};
-DECLARE_VM_GET_PAGE_PROT
-
void mark_rodata_ro(void)
{
unsigned long rodata_start = PFN_ALIGN(__start_rodata);
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 3/9] um: nommu: memory handling
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 1/9] x86/um: nommu: elf loader for fdpic Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 2/9] um: decouple MMU specific code from the common part Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 4/9] um: change machine name for uname output Johannes Berg
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
From: Hajime Tazaki <thehajime@gmail.com>
This commit adds memory operations on UML under !MMU environment.
Some part of the original UML code relying on CONFIG_MMU are excluded
from compilation when !CONFIG_MMU. Additionally, generic functions such as
uaccess, futex, memcpy/strnlen/strncpy can be used as user- and
kernel-space share the address space in !CONFIG_MMU mode.
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Link: https://patch.msgid.link/0e06cec4e7b715cd3c0a3fa8bec7e00c4e4c27ec.1770170302.git.thehajime@gmail.com
[drop unnecessary bits]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/include/asm/futex.h | 4 ++++
arch/um/include/asm/mmu.h | 3 +++
arch/um/include/asm/mmu_context.h | 2 ++
arch/um/include/asm/uaccess.h | 6 ++++--
arch/um/kernel/mem.c | 3 ++-
5 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/arch/um/include/asm/futex.h b/arch/um/include/asm/futex.h
index 780aa6bfc050..785fd6649aa2 100644
--- a/arch/um/include/asm/futex.h
+++ b/arch/um/include/asm/futex.h
@@ -7,8 +7,12 @@
#include <asm/errno.h>
+#ifdef CONFIG_MMU
int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr);
int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval);
+#else
+#include <asm-generic/futex.h>
+#endif
#endif
diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h
index 82a919132aff..c0b9ce3215c4 100644
--- a/arch/um/include/asm/mmu.h
+++ b/arch/um/include/asm/mmu.h
@@ -22,10 +22,13 @@ typedef struct mm_context {
unsigned long sync_tlb_range_from;
unsigned long sync_tlb_range_to;
+#ifndef CONFIG_MMU
+ unsigned long end_brk;
#ifdef CONFIG_BINFMT_ELF_FDPIC
unsigned long exec_fdpic_loadmap;
unsigned long interp_fdpic_loadmap;
#endif
+#endif /* !CONFIG_MMU */
} mm_context_t;
#define INIT_MM_CONTEXT(mm) \
diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h
index c727e56ba116..528b217da285 100644
--- a/arch/um/include/asm/mmu_context.h
+++ b/arch/um/include/asm/mmu_context.h
@@ -18,11 +18,13 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
{
}
+#ifdef CONFIG_MMU
#define init_new_context init_new_context
extern int init_new_context(struct task_struct *task, struct mm_struct *mm);
#define destroy_context destroy_context
extern void destroy_context(struct mm_struct *mm);
+#endif
#include <asm-generic/mmu_context.h>
diff --git a/arch/um/include/asm/uaccess.h b/arch/um/include/asm/uaccess.h
index 4417c8b1d37a..e493596f6663 100644
--- a/arch/um/include/asm/uaccess.h
+++ b/arch/um/include/asm/uaccess.h
@@ -18,6 +18,7 @@
#define __addr_range_nowrap(addr, size) \
((unsigned long) (addr) <= ((unsigned long) (addr) + (size)))
+#ifdef CONFIG_MMU
extern unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n);
extern unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n);
extern unsigned long __clear_user(void __user *mem, unsigned long len);
@@ -29,8 +30,6 @@ static inline int __access_ok(const void __user *ptr, unsigned long size);
#define INLINE_COPY_USER
-#include <asm-generic/uaccess.h>
-
static inline int __access_ok(const void __user *ptr, unsigned long size)
{
unsigned long addr = (unsigned long)ptr;
@@ -62,5 +61,8 @@ do { \
barrier(); \
current->thread.segv_continue = NULL; \
} while (0)
+#endif
+
+#include <asm-generic/uaccess.h>
#endif
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 4b84760b5e55..bc03bf3d114d 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -64,7 +64,8 @@ void __init arch_mm_preinit(void)
* to be turned on.
*/
brk_end = PAGE_ALIGN((unsigned long) sbrk(0));
- map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1,
+ !IS_ENABLED(CONFIG_MMU));
memblock_free((void *)brk_end, uml_reserved - brk_end);
uml_reserved = brk_end;
min_low_pfn = PFN_UP(__pa(uml_reserved));
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 4/9] um: change machine name for uname output
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (2 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 3/9] um: nommu: memory handling Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 5/9] x86/um/vdso: nommu: vdso memory update Johannes Berg
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
From: Hajime Tazaki <thehajime@gmail.com>
This commit tries to display MMU/!MMU mode from the output of uname(2)
so that users can distinguish which mode of UML is running right now.
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Link: https://patch.msgid.link/62314a61fd98febda7aafaa746f00eb0b16d1180.1770170302.git.thehajime@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/Makefile | 6 ++++++
arch/um/os-Linux/util.c | 3 ++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 937639edc295..1f85b73d4abb 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -148,6 +148,12 @@ export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) $(CC_FLAGS_
CLEAN_FILES += linux x.i gmon.out
MRPROPER_FILES += $(HOST_DIR)/include/generated
+ifeq ($(CONFIG_MMU),y)
+UTS_MACHINE := "um"
+else
+UTS_MACHINE := "um\(nommu\)"
+endif
+
archclean:
@find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
-o -name '*.gcov' \) -type f -print | xargs rm -f
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index e3ad71a0d13c..5fb26f5dfcb6 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -64,7 +64,8 @@ void setup_machinename(char *machine_out)
}
# endif
#endif
- strcpy(machine_out, host.machine);
+ strcat(machine_out, "/");
+ strcat(machine_out, host.machine);
}
void setup_hostinfo(char *buf, int len)
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 5/9] x86/um/vdso: nommu: vdso memory update
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (3 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 4/9] um: change machine name for uname output Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 6/9] um: further decouple MMU related code Johannes Berg
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
From: Hajime Tazaki <thehajime@gmail.com>
On !MMU mode, the address of vdso is accessible from userspace. This
commit implements the entry point by pointing a block of page address.
This commit also add memory permission configuration of vdso page to be
executable.
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Link: https://patch.msgid.link/1779dfb80f0e6fc25c001062a1e00cb661531c23.1770170302.git.thehajime@gmail.com
[remove print, add comment on #endif]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/x86/um/vdso/vma.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/x86/um/vdso/vma.c b/arch/x86/um/vdso/vma.c
index 51a2b9f2eca9..8e1f5ee44f4e 100644
--- a/arch/x86/um/vdso/vma.c
+++ b/arch/x86/um/vdso/vma.c
@@ -9,6 +9,7 @@
#include <asm/page.h>
#include <asm/elf.h>
#include <linux/init.h>
+#include <os.h>
unsigned long um_vdso_addr;
static struct page *um_vdso;
@@ -20,18 +21,25 @@ static int __init init_vdso(void)
{
BUG_ON(vdso_end - vdso_start > PAGE_SIZE);
- um_vdso_addr = task_size - PAGE_SIZE;
-
um_vdso = alloc_page(GFP_KERNEL);
if (!um_vdso)
panic("Cannot allocate vdso\n");
copy_page(page_address(um_vdso), vdso_start);
+#ifdef CONFIG_MMU
+ um_vdso_addr = task_size - PAGE_SIZE;
+#else
+ /* this is fine with NOMMU as everything is accessible */
+ um_vdso_addr = (unsigned long)page_address(um_vdso);
+ os_protect_memory((void *)um_vdso_addr, vdso_end - vdso_start, 1, 0, 1);
+#endif
+
return 0;
}
subsys_initcall(init_vdso);
+#ifdef CONFIG_MMU
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{
struct vm_area_struct *vma;
@@ -53,3 +61,4 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
return IS_ERR(vma) ? PTR_ERR(vma) : 0;
}
+#endif /* CONFIG_MMU */
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 6/9] um: further decouple MMU related code
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (4 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 5/9] x86/um/vdso: nommu: vdso memory update Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 7/9] um: nommu: add SMP futex operations Johannes Berg
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Since this approach shares more code with the MMU version
in nommu, further move some code around to be able to use
it in nommu (report_enomem) or be able to replace it (this
applies to mm_id, stack, sync). Also add empty inlines for
the TLB flushing and decouple trap.c code.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/include/asm/tlbflush.h | 20 +++
arch/um/kernel/Makefile | 2 +-
arch/um/kernel/physmem.c | 7 +
arch/um/kernel/skas/Makefile | 3 +-
arch/um/kernel/skas/mmu.c | 25 ++++
arch/um/kernel/skas/process.c | 26 ----
arch/um/kernel/tlb.c | 7 -
arch/um/kernel/trap-mmu.c | 238 +++++++++++++++++++++++++++++++++
arch/um/kernel/trap.c | 219 ------------------------------
9 files changed, 293 insertions(+), 254 deletions(-)
create mode 100644 arch/um/kernel/trap-mmu.c
diff --git a/arch/um/include/asm/tlbflush.h b/arch/um/include/asm/tlbflush.h
index 13a3009942be..f73b568a0859 100644
--- a/arch/um/include/asm/tlbflush.h
+++ b/arch/um/include/asm/tlbflush.h
@@ -30,6 +30,8 @@
* - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
*/
+#ifdef CONFIG_MMU
+
extern int um_tlb_sync(struct mm_struct *mm);
extern void flush_tlb_all(void);
@@ -56,4 +58,22 @@ static inline void flush_tlb_kernel_range(unsigned long start,
um_tlb_sync(&init_mm);
}
+#else /* !CONFIG_MMU */
+
+/*
+ * With NOMMU the kernel and userspace share a single host address space,
+ * so there is nothing to synchronise and all TLB flushes are no-ops.
+ */
+static inline int um_tlb_sync(struct mm_struct *mm) { return 0; }
+static inline void flush_tlb_all(void) { }
+static inline void flush_tlb_mm(struct mm_struct *mm) { }
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long address) { }
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end) { }
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end) { }
+
+#endif /* CONFIG_MMU */
+
#endif
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index d56fe6d829cc..5cd1bd4b23ac 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -19,7 +19,7 @@ obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
signal.o sysrq.o time.o trap.o \
um_arch.o umid.o kmsg_dump.o capflags.o skas/
obj-y += load_file.o
-obj-$(CONFIG_MMU) += mem-pgtable.o tlb.o
+obj-$(CONFIG_MMU) += mem-pgtable.o tlb.o trap-mmu.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index ae6ca373c261..ae9b8f3144b8 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -110,6 +110,13 @@ int phys_mapping(unsigned long phys, unsigned long long *offset_out)
}
EXPORT_SYMBOL(phys_mapping);
+void report_enomem(void)
+{
+ printk(KERN_ERR "UML ran out of memory on the host side! "
+ "This can happen due to a memory limitation or "
+ "vm.max_map_count has been reached.\n");
+}
+
static int __init uml_mem_setup(char *line, int *add)
{
char *retptr;
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 3384be42691f..28dd33580abc 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,8 +3,9 @@
# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
#
-obj-y := stub.o mmu.o process.o syscall.o uaccess.o \
+obj-y := stub.o process.o syscall.o \
stub_exe_embed.o
+obj-$(CONFIG_MMU) += mmu.o uaccess.o
# Stub executable
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index b5017096028b..facb88d1e393 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -12,6 +12,7 @@
#include <asm/pgalloc.h>
#include <asm/sections.h>
#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
#include <as-layout.h>
#include <os.h>
#include <skas.h>
@@ -40,6 +41,30 @@ void exit_turnstile(struct mm_id *mm_id)
mutex_unlock(__get_turnstile(mm_id));
}
+unsigned long current_stub_stack(void)
+{
+ if (current->mm == NULL)
+ return 0;
+
+ return current->mm->context.id.stack;
+}
+
+struct mm_id *current_mm_id(void)
+{
+ if (current->mm == NULL)
+ return NULL;
+
+ return ¤t->mm->context.id;
+}
+
+void current_mm_sync(void)
+{
+ if (current->mm == NULL)
+ return;
+
+ um_tlb_sync(current->mm);
+}
+
int init_new_context(struct task_struct *task, struct mm_struct *mm)
{
struct mm_id *new_id = &mm->context.id;
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 4a7673b0261a..dcdce50b4595 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -9,8 +9,6 @@
#include <linux/sched/task.h>
#include <linux/smp-internal.h>
-#include <asm/tlbflush.h>
-
#include <as-layout.h>
#include <kern.h>
#include <os.h>
@@ -42,30 +40,6 @@ int __init start_uml(void)
&init_task.thread.switch_buf);
}
-unsigned long current_stub_stack(void)
-{
- if (current->mm == NULL)
- return 0;
-
- return current->mm->context.id.stack;
-}
-
-struct mm_id *current_mm_id(void)
-{
- if (current->mm == NULL)
- return NULL;
-
- return ¤t->mm->context.id;
-}
-
-void current_mm_sync(void)
-{
- if (current->mm == NULL)
- return;
-
- um_tlb_sync(current->mm);
-}
-
static DEFINE_SPINLOCK(initial_jmpbuf_spinlock);
void initial_jmpbuf_lock(void)
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 1f175716b474..012bcc76168d 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -40,13 +40,6 @@ static int kern_unmap(struct mm_id *mm_idp,
return os_unmap_memory((void *)virt, len);
}
-void report_enomem(void)
-{
- printk(KERN_ERR "UML ran out of memory on the host side! "
- "This can happen due to a memory limitation or "
- "vm.max_map_count has been reached.\n");
-}
-
static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
unsigned long end,
struct vm_ops *ops)
diff --git a/arch/um/kernel/trap-mmu.c b/arch/um/kernel/trap-mmu.c
new file mode 100644
index 000000000000..a233a61e1801
--- /dev/null
+++ b/arch/um/kernel/trap-mmu.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ */
+
+#include <linux/mm.h>
+#include <linux/sched/signal.h>
+#include <linux/hardirq.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/sched/debug.h>
+#include <asm/current.h>
+#include <asm/tlbflush.h>
+#include <arch.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
+
+/*
+ * NOTE: UML does not have exception tables. As such, this is almost a copy
+ * of the code in mm/memory.c, only adjusting the logic to simply check whether
+ * we are coming from the kernel instead of doing an additional lookup in the
+ * exception table.
+ * We can do this simplification because we never get here if the exception was
+ * fixable.
+ */
+static inline bool get_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
+{
+ if (likely(mmap_read_trylock(mm)))
+ return true;
+
+ if (!is_user)
+ return false;
+
+ return !mmap_read_lock_killable(mm);
+}
+
+static inline bool mmap_upgrade_trylock(struct mm_struct *mm)
+{
+ /*
+ * We don't have this operation yet.
+ *
+ * It should be easy enough to do: it's basically a
+ * atomic_long_try_cmpxchg_acquire()
+ * from RWSEM_READER_BIAS -> RWSEM_WRITER_LOCKED, but
+ * it also needs the proper lockdep magic etc.
+ */
+ return false;
+}
+
+static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
+{
+ mmap_read_unlock(mm);
+ if (!is_user)
+ return false;
+
+ return !mmap_write_lock_killable(mm);
+}
+
+/*
+ * Helper for page fault handling.
+ *
+ * This is kind of equivalend to "mmap_read_lock()" followed
+ * by "find_extend_vma()", except it's a lot more careful about
+ * the locking (and will drop the lock on failure).
+ *
+ * For example, if we have a kernel bug that causes a page
+ * fault, we don't want to just use mmap_read_lock() to get
+ * the mm lock, because that would deadlock if the bug were
+ * to happen while we're holding the mm lock for writing.
+ *
+ * So this checks the exception tables on kernel faults in
+ * order to only do this all for instructions that are actually
+ * expected to fault.
+ *
+ * We can also actually take the mm lock for writing if we
+ * need to extend the vma, which helps the VM layer a lot.
+ */
+static struct vm_area_struct *
+um_lock_mm_and_find_vma(struct mm_struct *mm,
+ unsigned long addr, bool is_user)
+{
+ struct vm_area_struct *vma;
+
+ if (!get_mmap_lock_carefully(mm, is_user))
+ return NULL;
+
+ vma = find_vma(mm, addr);
+ if (likely(vma && (vma->vm_start <= addr)))
+ return vma;
+
+ /*
+ * Well, dang. We might still be successful, but only
+ * if we can extend a vma to do so.
+ */
+ if (!vma || !(vma->vm_flags & VM_GROWSDOWN)) {
+ mmap_read_unlock(mm);
+ return NULL;
+ }
+
+ /*
+ * We can try to upgrade the mmap lock atomically,
+ * in which case we can continue to use the vma
+ * we already looked up.
+ *
+ * Otherwise we'll have to drop the mmap lock and
+ * re-take it, and also look up the vma again,
+ * re-checking it.
+ */
+ if (!mmap_upgrade_trylock(mm)) {
+ if (!upgrade_mmap_lock_carefully(mm, is_user))
+ return NULL;
+
+ vma = find_vma(mm, addr);
+ if (!vma)
+ goto fail;
+ if (vma->vm_start <= addr)
+ goto success;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto fail;
+ }
+
+ if (expand_stack_locked(vma, addr))
+ goto fail;
+
+success:
+ mmap_write_downgrade(mm);
+ return vma;
+
+fail:
+ mmap_write_unlock(mm);
+ return NULL;
+}
+
+/*
+ * Note this is constrained to return 0, -EFAULT, -EACCES, -ENOMEM by
+ * segv().
+ */
+int handle_page_fault(unsigned long address, unsigned long ip,
+ int is_write, int is_user, int *code_out)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ pmd_t *pmd;
+ pte_t *pte;
+ int err = -EFAULT;
+ unsigned int flags = FAULT_FLAG_DEFAULT;
+
+ *code_out = SEGV_MAPERR;
+
+ /*
+ * If the fault was with pagefaults disabled, don't take the fault, just
+ * fail.
+ */
+ if (faulthandler_disabled())
+ goto out_nosemaphore;
+
+ if (is_user)
+ flags |= FAULT_FLAG_USER;
+retry:
+ vma = um_lock_mm_and_find_vma(mm, address, is_user);
+ if (!vma)
+ goto out_nosemaphore;
+
+ *code_out = SEGV_ACCERR;
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto out;
+ flags |= FAULT_FLAG_WRITE;
+ } else {
+ /* Don't require VM_READ|VM_EXEC for write faults! */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto out;
+ }
+
+ do {
+ vm_fault_t fault;
+
+ fault = handle_mm_fault(vma, address, flags, NULL);
+
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ goto out_nosemaphore;
+
+ /* The fault is fully completed (including releasing mmap lock) */
+ if (fault & VM_FAULT_COMPLETED)
+ return 0;
+
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM) {
+ goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGSEGV) {
+ goto out;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ err = -EACCES;
+ goto out;
+ }
+ BUG();
+ }
+ if (fault & VM_FAULT_RETRY) {
+ flags |= FAULT_FLAG_TRIED;
+
+ goto retry;
+ }
+
+ pmd = pmd_off(mm, address);
+ pte = pte_offset_kernel(pmd, address);
+ } while (!pte_present(*pte));
+ err = 0;
+ /*
+ * The below warning was added in place of
+ * pte_mkyoung(); if (is_write) pte_mkdirty();
+ * If it's triggered, we'd see normally a hang here (a clean pte is
+ * marked read-only to emulate the dirty bit).
+ * However, the generic code can mark a PTE writable but clean on a
+ * concurrent read fault, triggering this harmlessly. So comment it out.
+ */
+#if 0
+ WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
+#endif
+
+out:
+ mmap_read_unlock(mm);
+out_nosemaphore:
+ return err;
+
+out_of_memory:
+ /*
+ * We ran out of memory, call the OOM killer, and return the userspace
+ * (which will retry the fault, or kill us if we got oom-killed).
+ */
+ mmap_read_unlock(mm);
+ if (!is_user)
+ goto out_nosemaphore;
+ pagefault_out_of_memory();
+ return 0;
+}
+
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 177615820a4c..ab60bab8d987 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -17,225 +17,6 @@
#include <os.h>
#include <skas.h>
-/*
- * NOTE: UML does not have exception tables. As such, this is almost a copy
- * of the code in mm/memory.c, only adjusting the logic to simply check whether
- * we are coming from the kernel instead of doing an additional lookup in the
- * exception table.
- * We can do this simplification because we never get here if the exception was
- * fixable.
- */
-static inline bool get_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
-{
- if (likely(mmap_read_trylock(mm)))
- return true;
-
- if (!is_user)
- return false;
-
- return !mmap_read_lock_killable(mm);
-}
-
-static inline bool mmap_upgrade_trylock(struct mm_struct *mm)
-{
- /*
- * We don't have this operation yet.
- *
- * It should be easy enough to do: it's basically a
- * atomic_long_try_cmpxchg_acquire()
- * from RWSEM_READER_BIAS -> RWSEM_WRITER_LOCKED, but
- * it also needs the proper lockdep magic etc.
- */
- return false;
-}
-
-static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
-{
- mmap_read_unlock(mm);
- if (!is_user)
- return false;
-
- return !mmap_write_lock_killable(mm);
-}
-
-/*
- * Helper for page fault handling.
- *
- * This is kind of equivalend to "mmap_read_lock()" followed
- * by "find_extend_vma()", except it's a lot more careful about
- * the locking (and will drop the lock on failure).
- *
- * For example, if we have a kernel bug that causes a page
- * fault, we don't want to just use mmap_read_lock() to get
- * the mm lock, because that would deadlock if the bug were
- * to happen while we're holding the mm lock for writing.
- *
- * So this checks the exception tables on kernel faults in
- * order to only do this all for instructions that are actually
- * expected to fault.
- *
- * We can also actually take the mm lock for writing if we
- * need to extend the vma, which helps the VM layer a lot.
- */
-static struct vm_area_struct *
-um_lock_mm_and_find_vma(struct mm_struct *mm,
- unsigned long addr, bool is_user)
-{
- struct vm_area_struct *vma;
-
- if (!get_mmap_lock_carefully(mm, is_user))
- return NULL;
-
- vma = find_vma(mm, addr);
- if (likely(vma && (vma->vm_start <= addr)))
- return vma;
-
- /*
- * Well, dang. We might still be successful, but only
- * if we can extend a vma to do so.
- */
- if (!vma || !(vma->vm_flags & VM_GROWSDOWN)) {
- mmap_read_unlock(mm);
- return NULL;
- }
-
- /*
- * We can try to upgrade the mmap lock atomically,
- * in which case we can continue to use the vma
- * we already looked up.
- *
- * Otherwise we'll have to drop the mmap lock and
- * re-take it, and also look up the vma again,
- * re-checking it.
- */
- if (!mmap_upgrade_trylock(mm)) {
- if (!upgrade_mmap_lock_carefully(mm, is_user))
- return NULL;
-
- vma = find_vma(mm, addr);
- if (!vma)
- goto fail;
- if (vma->vm_start <= addr)
- goto success;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto fail;
- }
-
- if (expand_stack_locked(vma, addr))
- goto fail;
-
-success:
- mmap_write_downgrade(mm);
- return vma;
-
-fail:
- mmap_write_unlock(mm);
- return NULL;
-}
-
-/*
- * Note this is constrained to return 0, -EFAULT, -EACCES, -ENOMEM by
- * segv().
- */
-int handle_page_fault(unsigned long address, unsigned long ip,
- int is_write, int is_user, int *code_out)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- pmd_t *pmd;
- pte_t *pte;
- int err = -EFAULT;
- unsigned int flags = FAULT_FLAG_DEFAULT;
-
- *code_out = SEGV_MAPERR;
-
- /*
- * If the fault was with pagefaults disabled, don't take the fault, just
- * fail.
- */
- if (faulthandler_disabled())
- goto out_nosemaphore;
-
- if (is_user)
- flags |= FAULT_FLAG_USER;
-retry:
- vma = um_lock_mm_and_find_vma(mm, address, is_user);
- if (!vma)
- goto out_nosemaphore;
-
- *code_out = SEGV_ACCERR;
- if (is_write) {
- if (!(vma->vm_flags & VM_WRITE))
- goto out;
- flags |= FAULT_FLAG_WRITE;
- } else {
- /* Don't require VM_READ|VM_EXEC for write faults! */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto out;
- }
-
- do {
- vm_fault_t fault;
-
- fault = handle_mm_fault(vma, address, flags, NULL);
-
- if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
- goto out_nosemaphore;
-
- /* The fault is fully completed (including releasing mmap lock) */
- if (fault & VM_FAULT_COMPLETED)
- return 0;
-
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM) {
- goto out_of_memory;
- } else if (fault & VM_FAULT_SIGSEGV) {
- goto out;
- } else if (fault & VM_FAULT_SIGBUS) {
- err = -EACCES;
- goto out;
- }
- BUG();
- }
- if (fault & VM_FAULT_RETRY) {
- flags |= FAULT_FLAG_TRIED;
-
- goto retry;
- }
-
- pmd = pmd_off(mm, address);
- pte = pte_offset_kernel(pmd, address);
- } while (!pte_present(*pte));
- err = 0;
- /*
- * The below warning was added in place of
- * pte_mkyoung(); if (is_write) pte_mkdirty();
- * If it's triggered, we'd see normally a hang here (a clean pte is
- * marked read-only to emulate the dirty bit).
- * However, the generic code can mark a PTE writable but clean on a
- * concurrent read fault, triggering this harmlessly. So comment it out.
- */
-#if 0
- WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
-#endif
-
-out:
- mmap_read_unlock(mm);
-out_nosemaphore:
- return err;
-
-out_of_memory:
- /*
- * We ran out of memory, call the OOM killer, and return the userspace
- * (which will retry the fault, or kill us if we got oom-killed).
- */
- mmap_read_unlock(mm);
- if (!is_user)
- goto out_nosemaphore;
- pagefault_out_of_memory();
- return 0;
-}
-
static void show_segv_info(struct uml_pt_regs *regs)
{
struct task_struct *tsk = current;
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 7/9] um: nommu: add SMP futex operations
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (5 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 6/9] um: further decouple MMU related code Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-20 19:06 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 8/9] um: nommu: add userspace runner processes Johannes Berg
` (2 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
The asm-generic futex implementation only supports UP operations,
and the normal (MMU) implementation from uaccess.c isn't built
nor would it work.
Since NOMMU shares address space anyway, it's all trivial and we
can just make a trivial implementation.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/include/asm/futex.h | 53 ++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/arch/um/include/asm/futex.h b/arch/um/include/asm/futex.h
index 785fd6649aa2..ecfaad61acc0 100644
--- a/arch/um/include/asm/futex.h
+++ b/arch/um/include/asm/futex.h
@@ -12,7 +12,58 @@ int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval);
#else
+#include <linux/atomic.h>
#include <asm-generic/futex.h>
-#endif
+
+#ifdef CONFIG_SMP
+static inline int
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
+{
+ u32 oldval, newval;
+ u32 *p = (u32 __force *)uaddr;
+
+ do {
+ oldval = READ_ONCE(*p);
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ newval = oparg;
+ break;
+ case FUTEX_OP_ADD:
+ newval = oldval + oparg;
+ break;
+ case FUTEX_OP_OR:
+ newval = oldval | oparg;
+ break;
+ case FUTEX_OP_ANDN:
+ newval = oldval & ~oparg;
+ break;
+ case FUTEX_OP_XOR:
+ newval = oldval ^ oparg;
+ break;
+ default:
+ return -ENOSYS;
+ }
+ } while (!try_cmpxchg(p, &oldval, newval));
+
+ *oval = oldval;
+ return 0;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ u32 *p = (u32 __force *)uaddr;
+
+ /* FIXME - shouldn't it be *uval = cmpxchg()? */
+ *uval = *p;
+ cmpxchg(p, oldval, newval);
+
+ return 0;
+}
+#endif /* CONFIG_SMP */
+
+#endif /* CONFIG_MMU */
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 8/9] um: nommu: add userspace runner processes
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (6 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 7/9] um: nommu: add SMP futex operations Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-22 1:30 ` Hajime Tazaki
2026-07-20 18:26 ` [RFC PATCH 9/9] um: nommu: plug nommu code into build system Johannes Berg
2026-07-22 0:39 ` [RFC PATCH 0/9] simplified UML/NOMMU approach Hajime Tazaki
9 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
For NOMMU there are not separate address spaces for
each userspace process group, which on the one hand
means we cannot start them on demand, but on the
other means we can just have one for each (virtual)
CPU, and map all of the memory into them.
Implement such processes, and the remaining bits
needed to compile the kernel without CONFIG_MMU.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/kernel/Makefile | 3 ++
arch/um/kernel/skas/Makefile | 3 ++
arch/um/kernel/skas/nommu.c | 91 ++++++++++++++++++++++++++++++++++++
arch/um/kernel/smp.c | 3 +-
arch/um/kernel/time.c | 3 +-
arch/um/kernel/trap-nommu.c | 13 ++++++
6 files changed, 114 insertions(+), 2 deletions(-)
create mode 100644 arch/um/kernel/skas/nommu.c
create mode 100644 arch/um/kernel/trap-nommu.c
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 5cd1bd4b23ac..b087b4278173 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -20,6 +20,9 @@ obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
um_arch.o umid.o kmsg_dump.o capflags.o skas/
obj-y += load_file.o
obj-$(CONFIG_MMU) += mem-pgtable.o tlb.o trap-mmu.o
+ifneq ($(CONFIG_MMU),y)
+obj-y += trap-nommu.o
+endif
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 28dd33580abc..c098d087c3f2 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -6,6 +6,9 @@
obj-y := stub.o process.o syscall.o \
stub_exe_embed.o
obj-$(CONFIG_MMU) += mmu.o uaccess.o
+ifneq ($(CONFIG_MMU),y)
+obj-y += nommu.o
+endif
# Stub executable
diff --git a/arch/um/kernel/skas/nommu.c b/arch/um/kernel/skas/nommu.c
new file mode 100644
index 000000000000..80d5c4eaa96b
--- /dev/null
+++ b/arch/um/kernel/skas/nommu.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/cpumask.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/mutex.h>
+#include <linux/panic.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <as-layout.h>
+#include <mem.h>
+#include <os.h>
+#include <skas.h>
+#include <mm_id.h>
+
+struct nommu_runner {
+ struct mm_id mm_id;
+ struct mutex turnstile;
+};
+
+static struct nommu_runner nommu_runners[NR_CPUS];
+
+static struct nommu_runner *this_runner(void)
+{
+ return &nommu_runners[raw_smp_processor_id()];
+}
+
+struct mutex *__get_turnstile(struct mm_id *mm_id)
+{
+ return &container_of(mm_id, struct nommu_runner, mm_id)->turnstile;
+}
+
+void enter_turnstile(struct mm_id *mm_id)
+{
+ mutex_lock(__get_turnstile(mm_id));
+}
+
+void exit_turnstile(struct mm_id *mm_id)
+{
+ mutex_unlock(__get_turnstile(mm_id));
+}
+
+unsigned long current_stub_stack(void)
+{
+ return this_runner()->mm_id.stack;
+}
+
+struct mm_id *current_mm_id(void)
+{
+ return &this_runner()->mm_id;
+}
+
+void current_mm_sync(void)
+{
+}
+
+static int __init nommu_start_runners(void)
+{
+ unsigned long long offset;
+ struct nommu_runner *r;
+ int cpu, err, fd;
+
+ fd = phys_mapping(uml_reserved - uml_physmem, &offset);
+
+ for_each_possible_cpu(cpu) {
+ r = &nommu_runners[cpu];
+ mutex_init(&r->turnstile);
+
+ r->mm_id.stack = __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ ilog2(STUB_DATA_PAGES));
+ if (!r->mm_id.stack)
+ panic("OOM allocating userspace stack for CPU %d", cpu);
+
+ err = start_userspace(&r->mm_id);
+ if (err < 0)
+ panic("userspace startup for CPU %d failed: %d",
+ cpu, err);
+
+ map(&r->mm_id, uml_reserved, high_physmem - uml_reserved,
+ UM_PROT_READ | UM_PROT_WRITE | UM_PROT_EXEC, fd, offset);
+
+ err = syscall_stub_flush(&r->mm_id);
+ if (err < 0)
+ panic("physmem map/flush failed for CPU%d: %d",
+ cpu, err);
+ }
+
+ return 0;
+}
+arch_initcall(nommu_start_runners);
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index f1e52b7348fb..92ea1beaed8b 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -20,6 +20,7 @@
#include <init.h>
#include <kern.h>
#include <os.h>
+#include <skas.h>
#include <smp.h>
enum {
@@ -66,7 +67,7 @@ static void ipi_handler(int vector, struct uml_pt_regs *regs)
irq_enter();
if (current->mm)
- os_alarm_process(current->mm->context.id.pid);
+ os_alarm_process(current_mm_id()->pid);
switch (vector) {
case UML_IPI_RES:
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index b344a36b44eb..d620b6d6310a 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -19,6 +19,7 @@
#include <asm/param.h>
#include <kern_util.h>
#include <os.h>
+#include <skas.h>
#include <linux/delay.h>
#include <linux/time-internal.h>
#include <linux/um_timetravel.h>
@@ -873,7 +874,7 @@ static irqreturn_t um_timer(int irq, void *dev)
if (time_travel_mode != TT_MODE_INFCPU &&
time_travel_mode != TT_MODE_EXTERNAL &&
get_current()->mm)
- os_alarm_process(get_current()->mm->context.id.pid);
+ os_alarm_process(current_mm_id()->pid);
evt->event_handler(evt);
diff --git a/arch/um/kernel/trap-nommu.c b/arch/um/kernel/trap-nommu.c
new file mode 100644
index 000000000000..891a9cefa935
--- /dev/null
+++ b/arch/um/kernel/trap-nommu.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <shared/kern_util.h>
+
+int handle_page_fault(unsigned long address, unsigned long ip,
+ int is_write, int is_user, int *code_out)
+{
+ /* everything that's valid is already mapped in NOMMU */
+ *code_out = SEGV_MAPERR;
+ return -EFAULT;
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [RFC PATCH 9/9] um: nommu: plug nommu code into build system
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (7 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 8/9] um: nommu: add userspace runner processes Johannes Berg
@ 2026-07-20 18:26 ` Johannes Berg
2026-07-22 0:39 ` [RFC PATCH 0/9] simplified UML/NOMMU approach Hajime Tazaki
9 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 18:26 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
From: Hajime Tazaki <thehajime@gmail.com>
Add nommu kernel for um build. defconfig is also provided.
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Link: https://patch.msgid.link/d6057e2fb8584671e259fbc2d94959e2b04117db.1770170302.git.thehajime@gmail.com
[drop defconfig file, minor adjustments/fixes]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
arch/um/Kconfig | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index d9541d13d9eb..d17bcdd200c4 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -17,9 +17,9 @@ config UML
select ARCH_HAS_KCOV
select ARCH_HAS_STRNCPY_FROM_USER
select ARCH_HAS_STRNLEN_USER
- select ARCH_HAS_STRICT_KERNEL_RWX
+ select ARCH_HAS_STRICT_KERNEL_RWX if MMU
select HAVE_ARCH_AUDITSYSCALL
- select HAVE_ARCH_KASAN if X86_64
+ select HAVE_ARCH_KASAN if X86_64 && MMU
select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ASM_MODVERSIONS
@@ -37,18 +37,23 @@ config UML
select ARCH_SUPPORTS_LTO_CLANG_THIN
select TRACE_IRQFLAGS_SUPPORT
select TTY # Needed for line.c
- select HAVE_ARCH_VMAP_STACK
+ select HAVE_ARCH_VMAP_STACK if MMU
select HAVE_RUST
select ARCH_HAS_UBSAN
select HAVE_ARCH_TRACEHOOK
select HAVE_SYSCALL_TRACEPOINTS
select THREAD_INFO_IN_TASK
select SPARSE_IRQ
- select MMU_GATHER_RCU_TABLE_FREE
+ select MMU_GATHER_RCU_TABLE_FREE if MMU
+ select UACCESS_MEMCPY if !MMU
+ select GENERIC_STRNLEN_USER if !MMU
+ select GENERIC_STRNCPY_FROM_USER if !MMU
config MMU
- bool
+ bool "MMU support"
default y
+ help
+ Turning this off allows a nommu build, say Y.
config UML_DMA_EMULATION
bool
@@ -229,8 +234,15 @@ config MAGIC_SYSRQ
The keys are documented in <file:Documentation/admin-guide/sysrq.rst>. Don't say Y
unless you really know what this hack does.
+config ARCH_FORCE_MAX_ORDER
+ int "Order of maximal physically contiguous allocations" if EXPERT
+ default "10" if MMU
+ default "16" if !MMU
+
config KERNEL_STACK_ORDER
int "Kernel stack size order"
+ default 3 if !MMU
+ range 3 10 if !MMU
default 2 if 64BIT
range 2 10 if 64BIT
default 1 if !64BIT
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [RFC PATCH 7/9] um: nommu: add SMP futex operations
2026-07-20 18:26 ` [RFC PATCH 7/9] um: nommu: add SMP futex operations Johannes Berg
@ 2026-07-20 19:06 ` Johannes Berg
2026-07-20 19:10 ` Johannes Berg
0 siblings, 1 reply; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 19:06 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
On Mon, 2026-07-20 at 20:26 +0200, Johannes Berg wrote:
>
> +static inline int
> +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
> +{
> + u32 oldval, newval;
> + u32 *p = (u32 __force *)uaddr;
> +
> + do {
> + oldval = READ_ONCE(*p);
> +
> + switch (op) {
> + case FUTEX_OP_SET:
> + newval = oparg;
> + break;
> + case FUTEX_OP_ADD:
> + newval = oldval + oparg;
> + break;
> + case FUTEX_OP_OR:
> + newval = oldval | oparg;
> + break;
> + case FUTEX_OP_ANDN:
> + newval = oldval & ~oparg;
> + break;
> + case FUTEX_OP_XOR:
> + newval = oldval ^ oparg;
> + break;
> + default:
> + return -ENOSYS;
> + }
> + } while (!try_cmpxchg(p, &oldval, newval));
> +
> + *oval = oldval;
Wait ... this is also garbage, it should just be the switch() and then
*oval = cmpxchg(p, oldval, newval);
not the loop...
> + /* FIXME - shouldn't it be *uval = cmpxchg()? */
> + *uval = *p;
> + cmpxchg(p, oldval, newval);
And yes, I think the FIXME is right and our uaccess.c implementation is
wrong.
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC PATCH 7/9] um: nommu: add SMP futex operations
2026-07-20 19:06 ` Johannes Berg
@ 2026-07-20 19:10 ` Johannes Berg
0 siblings, 0 replies; 14+ messages in thread
From: Johannes Berg @ 2026-07-20 19:10 UTC (permalink / raw)
To: linux-um; +Cc: Hajime Tazaki
On Mon, 2026-07-20 at 21:06 +0200, Johannes Berg wrote:
> On Mon, 2026-07-20 at 20:26 +0200, Johannes Berg wrote:
> >
> > +static inline int
> > +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
> > +{
> > + u32 oldval, newval;
> > + u32 *p = (u32 __force *)uaddr;
> > +
> > + do {
> > + oldval = READ_ONCE(*p);
> > +
> > + switch (op) {
> > + case FUTEX_OP_SET:
> > + newval = oparg;
> > + break;
> > + case FUTEX_OP_ADD:
> > + newval = oldval + oparg;
> > + break;
> > + case FUTEX_OP_OR:
> > + newval = oldval | oparg;
> > + break;
> > + case FUTEX_OP_ANDN:
> > + newval = oldval & ~oparg;
> > + break;
> > + case FUTEX_OP_XOR:
> > + newval = oldval ^ oparg;
> > + break;
> > + default:
> > + return -ENOSYS;
> > + }
> > + } while (!try_cmpxchg(p, &oldval, newval));
> > +
> > + *oval = oldval;
>
> Wait ... this is also garbage, it should just be the switch() and then
>
> *oval = cmpxchg(p, oldval, newval);
>
> not the loop...
Err, no. But our uaccess.c implementation here also seems wrong and
should be more like this one?
OK I'm confused, but I think we need to clean up uaccess.c before
implementing this for real...
johannes
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC PATCH 0/9] simplified UML/NOMMU approach
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
` (8 preceding siblings ...)
2026-07-20 18:26 ` [RFC PATCH 9/9] um: nommu: plug nommu code into build system Johannes Berg
@ 2026-07-22 0:39 ` Hajime Tazaki
9 siblings, 0 replies; 14+ messages in thread
From: Hajime Tazaki @ 2026-07-22 0:39 UTC (permalink / raw)
To: johannes; +Cc: linux-um
Hello,
On Tue, 21 Jul 2026 03:26:50 +0900,
Johannes Berg wrote:
> After Hajime's talk at netdevconf 0x1A I was this time really
> tempted into implementing an approach to NOMMU UML that I'd
> thought about quite a while ago, and here's the resulting
> code. I had prototyped some of this with LLM help, but now
> have pretty much reworked most of it (except boilerplate).
>
> Instead of using a wholly new architectural interface, new
> process/thread handling, new seccomp machinery etc. this
> just reuses all the existing infrastructure (we're not in
> fact trying to run UML on nommu, but run _as_ nommu), but
> makes runner processes for each CPU instead of each userspace
> MM (as it would be on MMU).
>
> This eventually results in a far simpler implementation that
> doesn't have all the complexity of the syscall handling yet
> again.
>
> It's also more capable:
> - continues working with ptrace
> - doesn't require disabling SMP
> (just has a runner per CPU)
> - should work on 32-bit (untested)
> - keeps physmem FD, which in theory should allow virtio
> PCI devices, but PCI doesn't build on !MMU right now
thanks, this is really nice.
I quickly read the patchset and found that [RFC PATCH 8/9] is the core
of your idea, which I agree with your point of simplicity, as well as
the list of compatible features of (the stock version of) UML.
I also understand the need of futex implementation instead of
asm-generic, which only works with !CONFIG_SMP.
I also quickly tested with my local tests (getpid bench, lmbench,
iperf/netperf, and LTP) and all looks fine. speed measurement is
mostly what I expected.
getpid (nsec)
----------------
native 421
um 31983
um-mmu(seccomp) 26753
um-nommu(seccomp) 3533
um-nommu-skas 27844
um-nommu-skas(seccomp) 26387
> However, it does go in an entirely different direction
> and while it doesn't entirely close off all things for
> optimisations wrt. syscall speed that the much older
> versions of the NOMMU patchset did, it does create the
> infrastructure in a way that doesn't make that easier.
>
> Personally, I think the only real use case for this
> whole thing is NOMMU testing (which was requested), and
> we don't really need everything else.
>
> Note: the futex thing seems odd. I mirrored the existing
> implementation, but I think it's just wrong. There's a
> FIXME in the code for now.
>
> It does boot ghcr.io/thehajime/alpine:3.20.3-um-nommu
> as was documented before.
What is your plan for this RFC ?
I'm pretty fine with this (skas nommu) mode for nommu UML; it
is certainly useful to detect more bugs if it is available in UML.
I would also like to ask maintainers if my nommu approach can be an
opt-in feature only when specific kernel config is added, probably
marking as '(EXPERIMENTAL)' or `if EXPERT` condition, as there is
potential benefits (speed, less host process use, etc.).
But if you (maintainers) wish and feel this as not an easy option,
I can work for it with later patches as an extension.
btw, maybe I need a better name for (my) nommu code using different
syscall handling, with regard to skas (i.e., separate kernel address
space) mode (e.g., CONFIG_UML_NOMMU_SAS (single address space) etc.).
-- Hajime
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC PATCH 8/9] um: nommu: add userspace runner processes
2026-07-20 18:26 ` [RFC PATCH 8/9] um: nommu: add userspace runner processes Johannes Berg
@ 2026-07-22 1:30 ` Hajime Tazaki
0 siblings, 0 replies; 14+ messages in thread
From: Hajime Tazaki @ 2026-07-22 1:30 UTC (permalink / raw)
To: johannes; +Cc: linux-um, johannes.berg
On Tue, 21 Jul 2026 03:26:58 +0900,
Johannes Berg wrote:
>
> From: Johannes Berg <johannes.berg@intel.com>
>
> For NOMMU there are not separate address spaces for
> each userspace process group, which on the one hand
> means we cannot start them on demand, but on the
> other means we can just have one for each (virtual)
> CPU, and map all of the memory into them.
>
> Implement such processes, and the remaining bits
> needed to compile the kernel without CONFIG_MMU.
I was wondering where kernel address is located in this mode.
although it doesn't have to be, under nommu, kernel address is located
in the same address space with all userspace processes in my
understanding.
the kernel address is accessible (danger but it's !MMU) from userspace
thus __access_ok() always returns 1. so just wondering what is the
case with this runner process approach.
a program accessing kernel address may fail (or crash in some case),
but with the runner it won't ?
-- Hajime
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-07-22 1:30 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 18:26 [RFC PATCH 0/9] simplified UML/NOMMU approach Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 1/9] x86/um: nommu: elf loader for fdpic Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 2/9] um: decouple MMU specific code from the common part Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 3/9] um: nommu: memory handling Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 4/9] um: change machine name for uname output Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 5/9] x86/um/vdso: nommu: vdso memory update Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 6/9] um: further decouple MMU related code Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 7/9] um: nommu: add SMP futex operations Johannes Berg
2026-07-20 19:06 ` Johannes Berg
2026-07-20 19:10 ` Johannes Berg
2026-07-20 18:26 ` [RFC PATCH 8/9] um: nommu: add userspace runner processes Johannes Berg
2026-07-22 1:30 ` Hajime Tazaki
2026-07-20 18:26 ` [RFC PATCH 9/9] um: nommu: plug nommu code into build system Johannes Berg
2026-07-22 0:39 ` [RFC PATCH 0/9] simplified UML/NOMMU approach Hajime Tazaki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox