Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Documentation/dev-tools/kunit/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ API Reference
test
resource
functionredirection
uapi
clk
of
platformdevice
Expand All @@ -32,6 +33,10 @@ Documentation/dev-tools/kunit/api/functionredirection.rst

- Documents the KUnit Function Redirection API

Documentation/dev-tools/kunit/api/uapi.rst

- Documents the KUnit Userspace testing API

Driver KUnit API
================

Expand Down
12 changes: 12 additions & 0 deletions Documentation/dev-tools/kunit/api/uapi.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. SPDX-License-Identifier: GPL-2.0

==================
Userspace Test API
==================

This file documents all of the userspace testing API.
Userspace tests should be built as :ref:`userprogs <kbuild_userprogs>` and included into the test
module or kernel as :ref:`blobs <kbuild_blobs>`.

.. kernel-doc:: include/kunit/uapi.h
:internal:
38 changes: 36 additions & 2 deletions Documentation/kbuild/makefiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,8 @@ otherwise the command line check will fail, and the target will
always be built.

If the target is already listed in the recognized syntax such as
obj-y/m, lib-y/m, extra-y/m, always-y/m, hostprogs, userprogs, Kbuild
automatically adds it to $(targets). Otherwise, the target must be
obj-y/m, lib-y/m, extra-y/m, always-y/m, hostprogs, userprogs, blobs,
Kbuild automatically adds it to $(targets). Otherwise, the target must be
explicitly added to $(targets).

Assignments to $(targets) are without $(obj)/ prefix. if_changed may be
Expand Down Expand Up @@ -891,6 +891,8 @@ This is possible in two ways:
This will tell kbuild to build lxdialog even if not referenced in
any rule.

.. _kbuild_userprogs:

Userspace Program support
=========================

Expand Down Expand Up @@ -974,6 +976,19 @@ When linking bpfilter_umh, it will be passed the extra option -static.

From command line, :ref:`USERCFLAGS and USERLDFLAGS <userkbuildflags>` will also be used.

Building userprogs against nolibc
---------------------------------

Not all kernel toolchains provide a libc.
Simple userprogs can be built against a very simple libc call "nolibc" provided
by the kernel source tree.
This requires ``CONFIG_HEADERS_INSTALL=y``.

Example::

# lib/kunit/Makefile
uapi-preinit-nolibc := $(CONFIG_ARCH_HAS_NOLIBC)

When userspace programs are actually built
------------------------------------------

Expand Down Expand Up @@ -1004,6 +1019,25 @@ There are two ways to do this.
This will tell Kbuild to build binderfs_example when it visits this
Makefile.

.. _kbuild_blobs:

Blob framework
==============

Kbuild supports wrapping source or generated files into object files which are linked
into the kernel and then accessed at runtime through ``include/linux/blob.h``.

Example::

obj-m := some-module.o
userprogs := some-userprog
blobs := some-userprog.blob.o
some-userprog.blob-symbol := some_userprog
some-module-y += some-userprog.blob.o

Kbuild will build the :ref:`userprog <kbuild_userprogs>` ``some-userprog`` and
link it into ``some-module`` from where it can be accessed as ``BLOB(some_userprog)``.

Kbuild clean infrastructure
===========================

Expand Down
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -13063,11 +13063,13 @@ Q: https://patchwork.kernel.org/project/linux-kbuild/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
F: Documentation/kbuild/
F: Makefile
F: include/linux/blob.h
F: scripts/*vmlinux*
F: scripts/Kbuild*
F: scripts/Makefile*
F: scripts/bash-completion/
F: scripts/basic/
F: scripts/blob-wrap.c
F: scripts/clang-tools/
F: scripts/dummy-tools/
F: scripts/include/
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1129,9 +1129,10 @@ ifneq ($(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS),)
LDFLAGS_vmlinux += --emit-relocs --discard-none
endif

# Align the bit size of userspace programs with the kernel
KBUILD_USERCFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
KBUILD_USERLDFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
# Align the bit size, byte order and architecture of userspace programs with the kernel
USERFLAGS_FROM_KERNEL := -m32 -m64 -mlittle-endian -mbig-endian --target=% -march=% -mabi=%
KBUILD_USERCFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))
KBUILD_USERLDFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS))

# userspace programs are linked via the compiler, use the correct linker
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_LD_IS_LLD),yy)
Expand Down
24 changes: 24 additions & 0 deletions include/kunit/uapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* KUnit Userspace testing API.
*
* Copyright (C) 2025, Linutronix GmbH.
* Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/

#ifndef _KUNIT_UAPI_H
#define _KUNIT_UAPI_H

struct blob;
struct kunit;

/**
* kunit_uapi_run_kselftest() - Run a userspace kselftest as part of kunit
* @test: The test context object.
* @executable: kselftest executable to run
*
* Runs the kselftest and forwards its TAP output and exit status to kunit.
*/
void kunit_uapi_run_kselftest(struct kunit *test, const struct blob *executable);

#endif /* _KUNIT_UAPI_H */
31 changes: 31 additions & 0 deletions include/linux/blob.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linkable blob API.
*
* Copyright (C) 2025, Linutronix GmbH.
* Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/

#ifndef _LINUX_BLOB_H
#define _LINUX_BLOB_H

#include <linux/args.h>
#include <linux/types.h>

struct blob {
const char *const path;
const u8 *data;
const u8 *end;
};

#define BLOB(_symbol) ({ \
extern const struct blob CONCATENATE(__blob_, _symbol); \
&CONCATENATE(__blob_, _symbol); \
})

static inline size_t blob_size(const struct blob *blob)
{
return blob->end - blob->data;
}

#endif /* _LINUX_BLOB_H */
7 changes: 7 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ config CC_CAN_LINK
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag)) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag))

config CC_CAN_LINK_STATIC
bool
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag) -static) if 64BIT
default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m32-flag) -static)

source "tools/include/nolibc/Kconfig.nolibc"

# Fixed in GCC 14, 13.3, 12.4 and 11.5
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
config GCC_ASM_GOTO_OUTPUT_BROKEN
Expand Down
4 changes: 0 additions & 4 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o
CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)

# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
# so we can't just use obj-$(CONFIG_KUNIT).
ifdef CONFIG_KUNIT
obj-y += kunit/
endif

ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
Expand Down
10 changes: 10 additions & 0 deletions lib/kunit/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,14 @@ config KUNIT_AUTORUN_ENABLED
In most cases this should be left as Y. Only if additional opt-in
behavior is needed should this be set to N.

config KUNIT_UAPI
def_bool y
depends on KUNIT=y
depends on CC_CAN_LINK_STATIC || ARCH_HAS_NOLIBC
select HEADERS_INSTALL
help
Enables support for building and running userspace selftests as part of kunit.
These tests should be statically linked and use kselftest.h or kselftest_harness.h
for status reporting.

endif # KUNIT
20 changes: 18 additions & 2 deletions lib/kunit/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@ kunit-objs += test.o \
device.o \
platform.o

userprogs += uapi-preinit
uapi-preinit-nolibc := $(CONFIG_ARCH_HAS_NOLIBC)
uapi-preinit-userccflags += -static \
-include include/generated/autoconf.h \
-include $(srctree)/tools/include/linux/kconfig.h
blobs += uapi-preinit.blob.o
uapi-preinit.blob-symbol := kunit_uapi_preinit
kunit-$(CONFIG_KUNIT_UAPI) += uapi.o uapi-preinit.blob.o

ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
endif

# KUnit 'hooks' are built-in even when KUnit is built as a module.
obj-y += hooks.o
obj-$(if $(CONFIG_KUNIT),y) += hooks.o

obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
obj-$(CONFIG_KUNIT_TEST) += platform-test.o
Expand All @@ -28,4 +37,11 @@ obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o
obj-$(CONFIG_KUNIT_TEST) += assert_test.o
endif

obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += kunit-example-test.o
userprogs += kunit-example-uapi
kunit-example-uapi-userccflags := -static
kunit-example-uapi-nolibc := $(CONFIG_ARCH_HAS_NOLIBC)
blobs += kunit-example-uapi.blob.o

obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += kunit-example-mod.o
kunit-example-mod-y += kunit-example-test.o
kunit-example-mod-$(CONFIG_KUNIT_UAPI) += kunit-example-uapi.blob.o
15 changes: 15 additions & 0 deletions lib/kunit/kunit-example-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
* Author: Brendan Higgins <brendanhiggins@google.com>
*/

#include <linux/blob.h>

#include <kunit/test.h>
#include <kunit/static_stub.h>
#include <kunit/uapi.h>

/*
* This is the most fundamental element of KUnit, the test case. A test case
Expand Down Expand Up @@ -277,6 +280,17 @@ static void example_slow_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
}

/*
* This test shows the usage of UAPI tests.
*/
static void example_uapi_test(struct kunit *test)
{
if (IS_ENABLED(CONFIG_KUNIT_UAPI))
kunit_uapi_run_kselftest(test, BLOB(kunit_example_uapi));
else
kunit_skip(test, "CONFIG_KUNIT_UAPI is not enabled");
}

/*
* Here we make a list of all the test cases we want to add to the test suite
* below.
Expand All @@ -297,6 +311,7 @@ static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_priv_test),
KUNIT_CASE_PARAM(example_params_test, example_gen_params),
KUNIT_CASE_SLOW(example_slow_test),
KUNIT_CASE(example_uapi_test),
{}
};

Expand Down
54 changes: 54 additions & 0 deletions lib/kunit/kunit-example-uapi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit Userspace example test.
*
* Copyright (C) 2025, Linutronix GmbH.
* Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*
* This is *userspace* code.
*/

#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#include "../../tools/testing/selftests/kselftest.h"

static void test_procfs(void)
{
char buf[256];
ssize_t r;
int fd;

fd = open("/proc/self/comm", O_RDONLY);
if (fd == -1) {
ksft_test_result_fail("procfs: open() failed: %s\n", strerror(errno));
return;
}

r = read(fd, buf, sizeof(buf));
close(fd);

if (r == -1) {
ksft_test_result_fail("procfs: read() failed: %s\n", strerror(errno));
return;
}

if (r != 16 || strncmp("kunit-example-u\n", buf, 16) != 0) {
ksft_test_result_fail("procfs: incorrect comm\n");
return;
}

ksft_test_result_pass("procfs\n");
}

int main(void)
{
ksft_print_header();
ksft_set_plan(4);
test_procfs();
ksft_test_result_pass("userspace test 2\n");
ksft_test_result_skip("userspace test 3: some reason\n");
ksft_test_result_pass("userspace test 4\n");
ksft_finished();
}
Loading
Loading