linux_kselftest-kunit-6.18-rc1

- A seven patch series adds a new parameterized test features
   KUnit parameterized tests currently support two primary methods for
   getting parameters:
     1.  Defining custom logic within a generate_params() function.
     2.  Using the KUNIT_ARRAY_PARAM() and KUNIT_ARRAY_PARAM_DESC()
         macros with a pre-defined static array and passing
         the created *_gen_params() to KUNIT_CASE_PARAM().
 
     These methods present limitations when dealing with dynamically
     generated parameter arrays, or in scenarios where populating parameters
     sequentially via generate_params() is inefficient or overly complex.
 
     These limitations are fixed with a parameterized test method.
 
 - Fixes issues in kunit build artifacts cleanup,
 - Fixes parsing skipped test problem in kselftest framework,
 - Enables PCI on UML without triggering WARN()
 - a few other fixes and adds support for new configs such as MIPS
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmjbB0QACgkQCwJExA0N
 QxxpUQ/8CslEjTv2+/LA122eGDtg8np61W1MTNEQslYyiobhZ9CXeFw4yJlTTb0w
 hShFK1pGAWgkVCVKIJOaeItY0hF3BIxyVtlQxDUKvukpMnLvZRI0KhG7p8aYnCq+
 jfQRy4gqwjaHyLQekQ1v6vRdHdTfh5mB6OUOCYa7QPQuKhOkBOaq2ZJ+9eFnkPXl
 KUGTcC3pL0jQQmaSgo7zFUbdGSq0JZkNbpMj0fAYB0zs+MSpfkAnQYEw3qaxU1/Z
 lu+CQdom+77Kt0r7UyEb6xUBeRveqYAWv6oFKq3CBzhlEGCkqVv6zgNg48qMC0QO
 cVW0E61u8bVAalhb7hOT3QsEp1k01Lr2N9/VBLP4LRb2HMlD2qlXDo6ftBjNgx/y
 m5Kukh1wQoOTaTJekdDMlaRXwApdn3MegheXE83n4dr44C5oyhlR8fFk/0Y6gSEU
 RKUg8ZwUNUhCdw4VgBn8zoSkK18D74feRoustmuMS00I/8to3iGvQ7kn3nz2fPMb
 AaZ6a2K95gk9TrD4UZdHF1aPHDudn3e8g6LdSOV/NoRNI9H+fXfhvxcLwW8WCqOw
 u5qfTxNUk4mPQrCs9hcDnWm9Ppuu5YeY989rKkA7j4z71dhyMOPynpOM+vXRijB8
 9zRcvyls87tgDAquIZvTp6Q/oEmi60OF40DRC9MjgOw0Iw7feIc=
 =VfHu
 -----END PGP SIGNATURE-----

Merge tag 'linux_kselftest-kunit-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kunit updates from Shuah Khan:

 - New parameterized test features

   KUnit parameterized tests supported two primary methods for getting
   parameters:

    - Defining custom logic within a generate_params() function.

    - Using the KUNIT_ARRAY_PARAM() and KUNIT_ARRAY_PARAM_DESC() macros
      with a pre-defined static array and passing the created
      *_gen_params() to KUNIT_CASE_PARAM().

   These methods present limitations when dealing with dynamically
   generated parameter arrays, or in scenarios where populating
   parameters sequentially via generate_params() is inefficient or
   overly complex.

   These limitations are fixed with a parameterized test method

 - Fix issues in kunit build artifacts cleanup

 - Fix parsing skipped test problem in kselftest framework

 - Enable PCI on UML without triggering WARN()

 - a few other fixes and adds support for new configs such as MIPS

* tag 'linux_kselftest-kunit-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  kunit: Extend kconfig help text for KUNIT_UML_PCI
  rust: kunit: allow `cfg` on `test`s
  kunit: qemu_configs: Add MIPS configurations
  kunit: Enable PCI on UML without triggering WARN()
  Documentation: kunit: Document new parameterized test features
  kunit: Add example parameterized test with direct dynamic parameter array setup
  kunit: Add example parameterized test with shared resource management using the Resource API
  kunit: Enable direct registration of parameter arrays to a KUnit test
  kunit: Pass parameterized test context to generate_params()
  kunit: Introduce param_init/exit for parameterized test context management
  kunit: Add parent kunit for parameterized test context
  kunit: tool: Accept --raw_output=full as an alias of 'all'
  kunit: tool: Parse skipped tests from kselftest.h
  kunit: Always descend into kunit directory during build
This commit is contained in:
Linus Torvalds 2025-10-01 19:15:11 -07:00
commit 30bbcb4470
20 changed files with 880 additions and 63 deletions

View File

@ -542,11 +542,31 @@ There is more boilerplate code involved, but it can:
Parameterized Testing
~~~~~~~~~~~~~~~~~~~~~
The table-driven testing pattern is common enough that KUnit has special
support for it.
To run a test case against multiple inputs, KUnit provides a parameterized
testing framework. This feature formalizes and extends the concept of
table-driven tests discussed previously.
By reusing the same ``cases`` array from above, we can write the test as a
"parameterized test" with the following.
A KUnit test is determined to be parameterized if a parameter generator function
is provided when registering the test case. A test user can either write their
own generator function or use one that is provided by KUnit. The generator
function is stored in ``kunit_case->generate_params`` and can be set using the
macros described in the section below.
To establish the terminology, a "parameterized test" is a test which is run
multiple times (once per "parameter" or "parameter run"). Each parameter run has
both its own independent ``struct kunit`` (the "parameter run context") and
access to a shared parent ``struct kunit`` (the "parameterized test context").
Passing Parameters to a Test
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are three ways to provide the parameters to a test:
Array Parameter Macros:
KUnit provides special support for the common table-driven testing pattern.
By applying either ``KUNIT_ARRAY_PARAM`` or ``KUNIT_ARRAY_PARAM_DESC`` to the
``cases`` array from the previous section, we can create a parameterized test
as shown below:
.. code-block:: c
@ -555,7 +575,7 @@ By reusing the same ``cases`` array from above, we can write the test as a
const char *str;
const char *sha1;
};
const struct sha1_test_case cases[] = {
static const struct sha1_test_case cases[] = {
{
.str = "hello world",
.sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
@ -590,6 +610,318 @@ By reusing the same ``cases`` array from above, we can write the test as a
{}
};
Custom Parameter Generator Function:
The generator function is responsible for generating parameters one-by-one
and has the following signature:
``const void* (*)(struct kunit *test, const void *prev, char *desc)``.
You can pass the generator function to the ``KUNIT_CASE_PARAM``
or ``KUNIT_CASE_PARAM_WITH_INIT`` macros.
The function receives the previously generated parameter as the ``prev`` argument
(which is ``NULL`` on the first call) and can also access the parameterized
test context passed as the ``test`` argument. KUnit calls this function
repeatedly until it returns ``NULL``, which signifies that a parameterized
test ended.
Below is an example of how it works:
.. code-block:: c
#define MAX_TEST_BUFFER_SIZE 8
// Example generator function. It produces a sequence of buffer sizes that
// are powers of two, starting at 1 (e.g., 1, 2, 4, 8).
static const void *buffer_size_gen_params(struct kunit *test, const void *prev, char *desc)
{
long prev_buffer_size = (long)prev;
long next_buffer_size = 1; // Start with an initial size of 1.
// Stop generating parameters if the limit is reached or exceeded.
if (prev_buffer_size >= MAX_TEST_BUFFER_SIZE)
return NULL;
// For subsequent calls, calculate the next size by doubling the previous one.
if (prev)
next_buffer_size = prev_buffer_size << 1;
return (void *)next_buffer_size;
}
// Simple test to validate that kunit_kzalloc provides zeroed memory.
static void buffer_zero_test(struct kunit *test)
{
long buffer_size = (long)test->param_value;
// Use kunit_kzalloc to allocate a zero-initialized buffer. This makes the
// memory "parameter run managed," meaning it's automatically cleaned up at
// the end of each parameter run.
int *buf = kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL);
// Ensure the allocation was successful.
KUNIT_ASSERT_NOT_NULL(test, buf);
// Loop through the buffer and confirm every element is zero.
for (int i = 0; i < buffer_size; i++)
KUNIT_EXPECT_EQ(test, buf[i], 0);
}
static struct kunit_case buffer_test_cases[] = {
KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params),
{}
};
Runtime Parameter Array Registration in the Init Function:
For scenarios where you might need to initialize a parameterized test, you
can directly register a parameter array to the parameterized test context.
To do this, you must pass the parameterized test context, the array itself,
the array size, and a ``get_description()`` function to the
``kunit_register_params_array()`` macro. This macro populates
``struct kunit_params`` within the parameterized test context, effectively
storing a parameter array object. The ``get_description()`` function will
be used for populating parameter descriptions and has the following signature:
``void (*)(struct kunit *test, const void *param, char *desc)``. Note that it
also has access to the parameterized test context.
.. important::
When using this way to register a parameter array, you will need to
manually pass ``kunit_array_gen_params()`` as the generator function to
``KUNIT_CASE_PARAM_WITH_INIT``. ``kunit_array_gen_params()`` is a KUnit
helper that will use the registered array to generate the parameters.
If needed, instead of passing the KUnit helper, you can also pass your
own custom generator function that utilizes the parameter array. To
access the parameter array from within the parameter generator
function use ``test->params_array.params``.
The ``kunit_register_params_array()`` macro should be called within a
``param_init()`` function that initializes the parameterized test and has
the following signature ``int (*)(struct kunit *test)``. For a detailed
explanation of this mechanism please refer to the "Adding Shared Resources"
section that is after this one. This method supports registering both
dynamically built and static parameter arrays.
The code snippet below shows the ``example_param_init_dynamic_arr`` test that
utilizes ``make_fibonacci_params()`` to create a dynamic array, which is then
registered using ``kunit_register_params_array()``. To see the full code
please refer to lib/kunit/kunit-example-test.c.
.. code-block:: c
/*
* Example of a parameterized test param_init() function that registers a dynamic
* array of parameters.
*/
static int example_param_init_dynamic_arr(struct kunit *test)
{
size_t seq_size;
int *fibonacci_params;
kunit_info(test, "initializing parameterized test\n");
seq_size = 6;
fibonacci_params = make_fibonacci_params(test, seq_size);
if (!fibonacci_params)
return -ENOMEM;
/*
* Passes the dynamic parameter array information to the parameterized test
* context struct kunit. The array and its metadata will be stored in
* test->parent->params_array. The array itself will be located in
* params_data.params.
*/
kunit_register_params_array(test, fibonacci_params, seq_size,
example_param_dynamic_arr_get_desc);
return 0;
}
static struct kunit_case example_test_cases[] = {
/*
* Note how we pass kunit_array_gen_params() to use the array we
* registered in example_param_init_dynamic_arr() to generate
* parameters.
*/
KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
kunit_array_gen_params,
example_param_init_dynamic_arr,
example_param_exit_dynamic_arr),
{}
};
Adding Shared Resources
^^^^^^^^^^^^^^^^^^^^^^^
All parameter runs in this framework hold a reference to the parameterized test
context, which can be accessed using the parent ``struct kunit`` pointer. The
parameterized test context is not used to execute any test logic itself; instead,
it serves as a container for shared resources.
It's possible to add resources to share between parameter runs within a
parameterized test by using ``KUNIT_CASE_PARAM_WITH_INIT``, to which you pass
custom ``param_init()`` and ``param_exit()`` functions. These functions run once
before and once after the parameterized test, respectively.
The ``param_init()`` function, with the signature ``int (*)(struct kunit *test)``,
can be used for adding resources to the ``resources`` or ``priv`` fields of
the parameterized test context, registering the parameter array, and any other
initialization logic.
The ``param_exit()`` function, with the signature ``void (*)(struct kunit *test)``,
can be used to release any resources that were not parameterized test managed (i.e.
not automatically cleaned up after the parameterized test ends) and for any other
exit logic.
Both ``param_init()`` and ``param_exit()`` are passed the parameterized test
context behind the scenes. However, the test case function receives the parameter
run context. Therefore, to manage and access shared resources from within a test
case function, you must use ``test->parent``.
For instance, finding a shared resource allocated by the Resource API requires
passing ``test->parent`` to ``kunit_find_resource()``. This principle extends to
all other APIs that might be used in the test case function, including
``kunit_kzalloc()``, ``kunit_kmalloc_array()``, and others (see
Documentation/dev-tools/kunit/api/test.rst and the
Documentation/dev-tools/kunit/api/resource.rst).
.. note::
The ``suite->init()`` function, which executes before each parameter run,
receives the parameter run context. Therefore, any resources set up in
``suite->init()`` are cleaned up after each parameter run.
The code below shows how you can add the shared resources. Note that this code
utilizes the Resource API, which you can read more about here:
Documentation/dev-tools/kunit/api/resource.rst. To see the full version of this
code please refer to lib/kunit/kunit-example-test.c.
.. code-block:: c
static int example_resource_init(struct kunit_resource *res, void *context)
{
... /* Code that allocates memory and stores context in res->data. */
}
/* This function deallocates memory for the kunit_resource->data field. */
static void example_resource_free(struct kunit_resource *res)
{
kfree(res->data);
}
/* This match function locates a test resource based on defined criteria. */
static bool example_resource_alloc_match(struct kunit *test, struct kunit_resource *res,
void *match_data)
{
return res->data && res->free == example_resource_free;
}
/* Function to initialize the parameterized test. */
static int example_param_init(struct kunit *test)
{
int ctx = 3; /* Data to be stored. */
void *data = kunit_alloc_resource(test, example_resource_init,
example_resource_free,
GFP_KERNEL, &ctx);
if (!data)
return -ENOMEM;
kunit_register_params_array(test, example_params_array,
ARRAY_SIZE(example_params_array));
return 0;
}
/* Example test that uses shared resources in test->resources. */
static void example_params_test_with_init(struct kunit *test)
{
int threshold;
const struct example_param *param = test->param_value;
/* Here we pass test->parent to access the parameterized test context. */
struct kunit_resource *res = kunit_find_resource(test->parent,
example_resource_alloc_match,
NULL);
threshold = *((int *)res->data);
KUNIT_ASSERT_LE(test, param->value, threshold);
kunit_put_resource(res);
}
static struct kunit_case example_test_cases[] = {
KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
example_param_init, NULL),
{}
};
As an alternative to using the KUnit Resource API for sharing resources, you can
place them in ``test->parent->priv``. This serves as a more lightweight method
for resource storage, best for scenarios where complex resource management is
not required.
As stated previously ``param_init()`` and ``param_exit()`` get the parameterized
test context. So, you can directly use ``test->priv`` within ``param_init/exit``
to manage shared resources. However, from within the test case function, you must
navigate up to the parent ``struct kunit`` i.e. the parameterized test context.
Therefore, you need to use ``test->parent->priv`` to access those same
resources.
The resources placed in ``test->parent->priv`` will need to be allocated in
memory to persist across the parameter runs. If memory is allocated using the
KUnit memory allocation APIs (described more in the "Allocating Memory" section
below), you won't need to worry about deallocation. The APIs will make the memory
parameterized test 'managed', ensuring that it will automatically get cleaned up
after the parameterized test concludes.
The code below demonstrates example usage of the ``priv`` field for shared
resources:
.. code-block:: c
static const struct example_param {
int value;
} example_params_array[] = {
{ .value = 3, },
{ .value = 2, },
{ .value = 1, },
{ .value = 0, },
};
/* Initialize the parameterized test context. */
static int example_param_init_priv(struct kunit *test)
{
int ctx = 3; /* Data to be stored. */
int arr_size = ARRAY_SIZE(example_params_array);
/*
* Allocate memory using kunit_kzalloc(). Since the `param_init`
* function receives the parameterized test context, this memory
* allocation will be scoped to the lifetime of the parameterized test.
*/
test->priv = kunit_kzalloc(test, sizeof(int), GFP_KERNEL);
/* Assign the context value to test->priv.*/
*((int *)test->priv) = ctx;
/* Register the parameter array. */
kunit_register_params_array(test, example_params_array, arr_size, NULL);
return 0;
}
static void example_params_test_with_init_priv(struct kunit *test)
{
int threshold;
const struct example_param *param = test->param_value;
/* By design, test->parent will not be NULL. */
KUNIT_ASSERT_NOT_NULL(test, test->parent);
/* Here we use test->parent->priv to access the shared resource. */
threshold = *(int *)test->parent->priv;
KUNIT_ASSERT_LE(test, param->value, threshold);
}
static struct kunit_case example_tests[] = {
KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv,
kunit_array_gen_params,
example_param_init_priv, NULL),
{}
};
Allocating Memory
-----------------

View File

@ -44,9 +44,9 @@ KUNIT_ARRAY_PARAM(pci_id, pciidlist, xe_pci_id_kunit_desc);
*
* Return: pointer to the next parameter or NULL if no more parameters
*/
const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc)
const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *prev, char *desc)
{
return graphics_ip_gen_params(prev, desc);
return graphics_ip_gen_params(test, prev, desc);
}
EXPORT_SYMBOL_IF_KUNIT(xe_pci_graphics_ip_gen_param);
@ -61,9 +61,9 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_graphics_ip_gen_param);
*
* Return: pointer to the next parameter or NULL if no more parameters
*/
const void *xe_pci_media_ip_gen_param(const void *prev, char *desc)
const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev, char *desc)
{
return media_ip_gen_params(prev, desc);
return media_ip_gen_params(test, prev, desc);
}
EXPORT_SYMBOL_IF_KUNIT(xe_pci_media_ip_gen_param);
@ -78,9 +78,9 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_media_ip_gen_param);
*
* Return: pointer to the next parameter or NULL if no more parameters
*/
const void *xe_pci_id_gen_param(const void *prev, char *desc)
const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc)
{
const struct pci_device_id *pci = pci_id_gen_params(prev, desc);
const struct pci_device_id *pci = pci_id_gen_params(test, prev, desc);
return pci->driver_data ? pci : NULL;
}
@ -159,7 +159,7 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_fake_device_init);
* Return: pointer to the next &struct xe_device ready to be used as a parameter
* or NULL if there are no more Xe devices on the system.
*/
const void *xe_pci_live_device_gen_param(const void *prev, char *desc)
const void *xe_pci_live_device_gen_param(struct kunit *test, const void *prev, char *desc)
{
const struct xe_device *xe = prev;
struct device *dev = xe ? xe->drm.dev : NULL;

View File

@ -7,6 +7,7 @@
#define _XE_PCI_TEST_H_
#include <linux/types.h>
#include <kunit/test.h>
#include "xe_platform_types.h"
#include "xe_sriov_types.h"
@ -25,9 +26,9 @@ struct xe_pci_fake_data {
int xe_pci_fake_device_init(struct xe_device *xe);
const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc);
const void *xe_pci_media_ip_gen_param(const void *prev, char *desc);
const void *xe_pci_id_gen_param(const void *prev, char *desc);
const void *xe_pci_live_device_gen_param(const void *prev, char *desc);
const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *prev, char *desc);
const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev, char *desc);
const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc);
const void *xe_pci_live_device_gen_param(struct kunit *test, const void *prev, char *desc);
#endif

View File

@ -92,6 +92,8 @@ struct kunit_attributes {
* @name: the name of the test case.
* @generate_params: the generator function for parameterized tests.
* @attr: the attributes associated with the test
* @param_init: The init function to run before a parameterized test.
* @param_exit: The exit function to run after a parameterized test.
*
* A test case is a function with the signature,
* ``void (*)(struct kunit *)``
@ -126,8 +128,11 @@ struct kunit_attributes {
struct kunit_case {
void (*run_case)(struct kunit *test);
const char *name;
const void* (*generate_params)(const void *prev, char *desc);
const void* (*generate_params)(struct kunit *test,
const void *prev, char *desc);
struct kunit_attributes attr;
int (*param_init)(struct kunit *test);
void (*param_exit)(struct kunit *test);
/* private: internal use only. */
enum kunit_status status;
@ -218,6 +223,31 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
.generate_params = gen_params, \
.attr = attributes, .module_name = KBUILD_MODNAME}
/**
* KUNIT_CASE_PARAM_WITH_INIT - Define a parameterized KUnit test case with custom
* param_init() and param_exit() functions.
* @test_name: The function implementing the test case.
* @gen_params: The function to generate parameters for the test case.
* @init: A reference to the param_init() function to run before a parameterized test.
* @exit: A reference to the param_exit() function to run after a parameterized test.
*
* Provides the option to register param_init() and param_exit() functions.
* param_init/exit will be passed the parameterized test context and run once
* before and once after the parameterized test. The init function can be used
* to add resources to share between parameter runs, pass parameter arrays,
* and any other setup logic. The exit function can be used to clean up resources
* that were not managed by the parameterized test, and any other teardown logic.
*
* Note: If you are registering a parameter array in param_init() with
* kunit_register_param_array() then you need to pass kunit_array_gen_params()
* to this as the generator function.
*/
#define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \
{ .run_case = test_name, .name = #test_name, \
.generate_params = gen_params, \
.param_init = init, .param_exit = exit, \
.module_name = KBUILD_MODNAME}
/**
* struct kunit_suite - describes a related collection of &struct kunit_case
*
@ -263,19 +293,39 @@ struct kunit_suite_set {
struct kunit_suite * const *end;
};
/* Stores the pointer to the parameter array and its metadata. */
struct kunit_params {
/*
* Reference to the parameter array for a parameterized test. This
* is NULL if a parameter array wasn't directly passed to the
* parameterized test context struct kunit via kunit_register_params_array().
*/
const void *params;
/* Reference to a function that gets the description of a parameter. */
void (*get_description)(struct kunit *test, const void *param, char *desc);
size_t num_params;
size_t elem_size;
};
/**
* struct kunit - represents a running instance of a test.
*
* @priv: for user to store arbitrary data. Commonly used to pass data
* created in the init function (see &struct kunit_suite).
* @parent: reference to the parent context of type struct kunit that can
* be used for storing shared resources.
* @params_array: for storing the parameter array.
*
* Used to store information about the current context under which the test
* is running. Most of this data is private and should only be accessed
* indirectly via public functions; the one exception is @priv which can be
* used by the test writer to store arbitrary data.
* indirectly via public functions; the exceptions are @priv, @parent and
* @params_array which can be used by the test writer to store arbitrary data,
* access the parent context, and to store the parameter array, respectively.
*/
struct kunit {
void *priv;
struct kunit *parent;
struct kunit_params params_array;
/* private: internal use only. */
const char *name; /* Read only after initialization! */
@ -346,6 +396,8 @@ void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr)
struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set,
struct kunit_suite_set suite_set);
const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc);
#if IS_BUILTIN(CONFIG_KUNIT)
int kunit_run_all_tests(void);
#else
@ -1674,9 +1726,12 @@ do { \
* Define function @name_gen_params which uses @array to generate parameters.
*/
#define KUNIT_ARRAY_PARAM(name, array, get_desc) \
static const void *name##_gen_params(const void *prev, char *desc) \
static const void *name##_gen_params(struct kunit *test, \
const void *prev, char *desc) \
{ \
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
if (!prev) \
kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \
if (__next - (array) < ARRAY_SIZE((array))) { \
void (*__get_desc)(typeof(__next), char *) = get_desc; \
if (__get_desc) \
@ -1695,9 +1750,12 @@ do { \
* Define function @name_gen_params which uses @array to generate parameters.
*/
#define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \
static const void *name##_gen_params(const void *prev, char *desc) \
static const void *name##_gen_params(struct kunit *test, \
const void *prev, char *desc) \
{ \
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
if (!prev) \
kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \
if (__next - (array) < ARRAY_SIZE((array))) { \
strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \
return __next; \
@ -1705,6 +1763,33 @@ do { \
return NULL; \
}
/**
* kunit_register_params_array() - Register parameter array for a KUnit test.
* @test: The KUnit test structure to which parameters will be added.
* @array: An array of test parameters.
* @param_count: Number of parameters.
* @get_desc: Function that generates a string description for a given parameter
* element.
*
* This macro initializes the @test's parameter array data, storing information
* including the parameter array, its count, the element size, and the parameter
* description function within `test->params_array`.
*
* Note: If using this macro in param_init(), kunit_array_gen_params()
* will then need to be manually provided as the parameter generator function to
* KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit
* function that uses the registered array to generate parameters
*/
#define kunit_register_params_array(test, array, param_count, get_desc) \
do { \
struct kunit *_test = (test); \
const typeof((array)[0]) * _params_ptr = &(array)[0]; \
_test->params_array.params = _params_ptr; \
_test->params_array.num_params = (param_count); \
_test->params_array.elem_size = sizeof(*_params_ptr); \
_test->params_array.get_description = (get_desc); \
} while (0)
// TODO(dlatypov@google.com): consider eventually migrating users to explicitly
// include resource.h themselves if they need it.
#include <kunit/resource.h>

View File

@ -1383,7 +1383,7 @@ static void test_atomic_builtins_missing_barrier(struct kunit *test)
* The thread counts are chosen to cover potentially interesting boundaries and
* corner cases (2 to 5), and then stress the system with larger counts.
*/
static const void *nthreads_gen_params(const void *prev, char *desc)
static const void *nthreads_gen_params(struct kunit *test, const void *prev, char *desc)
{
long nthreads = (long)prev;

View File

@ -109,11 +109,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

View File

@ -106,4 +106,15 @@ config KUNIT_DEFAULT_TIMEOUT
If unsure, the default timeout of 300 seconds is suitable for most
cases.
config KUNIT_UML_PCI
bool "KUnit UML PCI Support"
depends on UML
select UML_PCI
help
Enables the PCI subsystem on UML for use by KUnit tests.
Some KUnit tests require the PCI core which is not enabled by
default on UML.
If unsure, say N.
endif # KUNIT

View File

@ -17,7 +17,7 @@ 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

View File

@ -277,6 +277,218 @@ static void example_slow_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
}
/*
* This custom function allocates memory and sets the information we want
* stored in the kunit_resource->data field.
*/
static int example_resource_init(struct kunit_resource *res, void *context)
{
int *info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
*info = *(int *)context;
res->data = info;
return 0;
}
/*
* This function deallocates memory for the kunit_resource->data field.
*/
static void example_resource_free(struct kunit_resource *res)
{
kfree(res->data);
}
/*
* This match function is invoked by kunit_find_resource() to locate
* a test resource based on certain criteria.
*/
static bool example_resource_alloc_match(struct kunit *test,
struct kunit_resource *res,
void *match_data)
{
return res->data && res->free == example_resource_free;
}
/*
* This is an example of a function that provides a description for each of the
* parameters in a parameterized test.
*/
static void example_param_array_get_desc(struct kunit *test, const void *p, char *desc)
{
const struct example_param *param = p;
snprintf(desc, KUNIT_PARAM_DESC_SIZE,
"example check if %d is less than or equal to 3", param->value);
}
/*
* This function gets passed in the parameterized test context i.e. the
* struct kunit belonging to the parameterized test. You can use this function
* to add resources you want shared across the whole parameterized test or
* for additional setup.
*/
static int example_param_init(struct kunit *test)
{
int ctx = 3; /* Data to be stored. */
size_t arr_size = ARRAY_SIZE(example_params_array);
/*
* This allocates a struct kunit_resource, sets its data field to
* ctx, and adds it to the struct kunit's resources list. Note that
* this is parameterized test managed. So, it doesn't need to have
* a custom exit function to deallocation as it will get cleaned up at
* the end of the parameterized test.
*/
void *data = kunit_alloc_resource(test, example_resource_init, example_resource_free,
GFP_KERNEL, &ctx);
if (!data)
return -ENOMEM;
/*
* Pass the parameter array information to the parameterized test context
* struct kunit. Note that you will need to provide kunit_array_gen_params()
* as the generator function to KUNIT_CASE_PARAM_WITH_INIT() when registering
* a parameter array this route.
*/
kunit_register_params_array(test, example_params_array, arr_size,
example_param_array_get_desc);
return 0;
}
/*
* This is an example of a test that uses shared resources available in the
* parameterized test context.
*/
static void example_params_test_with_init(struct kunit *test)
{
int threshold;
struct kunit_resource *res;
const struct example_param *param = test->param_value;
/* By design, param pointer will not be NULL. */
KUNIT_ASSERT_NOT_NULL(test, param);
/*
* Here we pass test->parent to search for shared resources in the
* parameterized test context.
*/
res = kunit_find_resource(test->parent, example_resource_alloc_match, NULL);
KUNIT_ASSERT_NOT_NULL(test, res);
/* Since kunit_resource->data is a void pointer we need to typecast it. */
threshold = *((int *)res->data);
/* Assert that the parameter is less than or equal to a certain threshold. */
KUNIT_ASSERT_LE(test, param->value, threshold);
/* This decreases the reference count after calling kunit_find_resource(). */
kunit_put_resource(res);
}
/*
* Helper function to create a parameter array of Fibonacci numbers. This example
* highlights a parameter generation scenario that is:
* 1. Not feasible to fully pre-generate at compile time.
* 2. Challenging to implement with a standard generate_params() function,
* as it only provides the previous parameter, while Fibonacci requires
* access to two preceding values for calculation.
*/
static void *make_fibonacci_params(struct kunit *test, size_t seq_size)
{
int *seq;
if (seq_size <= 0)
return NULL;
/*
* Using kunit_kmalloc_array here ties the lifetime of the array to
* the parameterized test i.e. it will get automatically cleaned up
* by KUnit after the parameterized test finishes.
*/
seq = kunit_kmalloc_array(test, seq_size, sizeof(int), GFP_KERNEL);
if (!seq)
return NULL;
if (seq_size >= 1)
seq[0] = 0;
if (seq_size >= 2)
seq[1] = 1;
for (int i = 2; i < seq_size; i++)
seq[i] = seq[i - 1] + seq[i - 2];
return seq;
}
/*
* This is an example of a function that provides a description for each of the
* parameters.
*/
static void example_param_dynamic_arr_get_desc(struct kunit *test, const void *p, char *desc)
{
const int *fib_num = p;
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "fibonacci param: %d", *fib_num);
}
/*
* Example of a parameterized test param_init() function that registers a dynamic
* array of parameters.
*/
static int example_param_init_dynamic_arr(struct kunit *test)
{
size_t seq_size;
int *fibonacci_params;
kunit_info(test, "initializing parameterized test\n");
seq_size = 6;
fibonacci_params = make_fibonacci_params(test, seq_size);
if (!fibonacci_params)
return -ENOMEM;
/*
* Passes the dynamic parameter array information to the parameterized test
* context struct kunit. The array and its metadata will be stored in
* test->parent->params_array. The array itself will be located in
* params_data.params.
*
* Note that you will need to pass kunit_array_gen_params() as the
* generator function to KUNIT_CASE_PARAM_WITH_INIT() when registering
* a parameter array this route.
*/
kunit_register_params_array(test, fibonacci_params, seq_size,
example_param_dynamic_arr_get_desc);
return 0;
}
/*
* Example of a parameterized test param_exit() function that outputs a log
* at the end of the parameterized test. It could also be used for any other
* teardown logic.
*/
static void example_param_exit_dynamic_arr(struct kunit *test)
{
kunit_info(test, "exiting parameterized test\n");
}
/*
* Example of test that uses the registered dynamic array to perform assertions
* and expectations.
*/
static void example_params_test_with_init_dynamic_arr(struct kunit *test)
{
const int *param = test->param_value;
int param_val;
/* By design, param pointer will not be NULL. */
KUNIT_ASSERT_NOT_NULL(test, param);
param_val = *param;
KUNIT_EXPECT_EQ(test, param_val - param_val, 0);
}
/*
* Here we make a list of all the test cases we want to add to the test suite
* below.
@ -296,6 +508,11 @@ static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_static_stub_using_fn_ptr_test),
KUNIT_CASE(example_priv_test),
KUNIT_CASE_PARAM(example_params_test, example_gen_params),
KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
example_param_init, NULL),
KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
kunit_array_gen_params, example_param_init_dynamic_arr,
example_param_exit_dynamic_arr),
KUNIT_CASE_SLOW(example_slow_test),
{}
};

View File

@ -337,6 +337,14 @@ void __kunit_do_failed_assertion(struct kunit *test,
}
EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);
static void kunit_init_params(struct kunit *test)
{
test->params_array.params = NULL;
test->params_array.get_description = NULL;
test->params_array.num_params = 0;
test->params_array.elem_size = 0;
}
void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log)
{
spin_lock_init(&test->lock);
@ -347,6 +355,7 @@ void kunit_init_test(struct kunit *test, const char *name, struct string_stream
string_stream_clear(log);
test->status = KUNIT_SUCCESS;
test->status_comment[0] = '\0';
kunit_init_params(test);
}
EXPORT_SYMBOL_GPL(kunit_init_test);
@ -641,12 +650,44 @@ static void kunit_accumulate_stats(struct kunit_result_stats *total,
total->total += add.total;
}
const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc)
{
struct kunit_params *params_arr = &test->params_array;
const void *param;
if (test->param_index < params_arr->num_params) {
param = (char *)params_arr->params
+ test->param_index * params_arr->elem_size;
if (params_arr->get_description)
params_arr->get_description(test, param, desc);
return param;
}
return NULL;
}
EXPORT_SYMBOL_GPL(kunit_array_gen_params);
static void kunit_init_parent_param_test(struct kunit_case *test_case, struct kunit *test)
{
if (test_case->param_init) {
int err = test_case->param_init(test);
if (err) {
kunit_err(test_case, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
"# failed to initialize parent parameter test (%d)", err);
test->status = KUNIT_FAILURE;
test_case->status = KUNIT_FAILURE;
}
}
}
int kunit_run_tests(struct kunit_suite *suite)
{
char param_desc[KUNIT_PARAM_DESC_SIZE];
struct kunit_case *test_case;
struct kunit_result_stats suite_stats = { 0 };
struct kunit_result_stats total_stats = { 0 };
const void *curr_param;
/* Taint the kernel so we know we've run tests. */
add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
@ -677,41 +718,64 @@ int kunit_run_tests(struct kunit_suite *suite)
kunit_run_case_catch_errors(suite, test_case, &test);
kunit_update_stats(&param_stats, test.status);
} else {
kunit_init_parent_param_test(test_case, &test);
if (test_case->status == KUNIT_FAILURE) {
kunit_update_stats(&param_stats, test.status);
goto test_case_end;
}
/* Get initial param. */
param_desc[0] = '\0';
test.param_value = test_case->generate_params(NULL, param_desc);
/* TODO: Make generate_params try-catch */
curr_param = test_case->generate_params(&test, NULL, param_desc);
test_case->status = KUNIT_SKIPPED;
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
"KTAP version 1\n");
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
"# Subtest: %s", test_case->name);
if (test.params_array.params &&
test_case->generate_params == kunit_array_gen_params) {
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT
KUNIT_SUBTEST_INDENT "1..%zd\n",
test.params_array.num_params);
}
while (test.param_value) {
kunit_run_case_catch_errors(suite, test_case, &test);
while (curr_param) {
struct kunit param_test = {
.param_value = curr_param,
.param_index = ++test.param_index,
.parent = &test,
};
kunit_init_test(&param_test, test_case->name, test_case->log);
kunit_run_case_catch_errors(suite, test_case, &param_test);
if (param_desc[0] == '\0') {
snprintf(param_desc, sizeof(param_desc),
"param-%d", test.param_index);
"param-%d", param_test.param_index);
}
kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM,
test.status,
test.param_index + 1,
kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
param_test.status,
param_test.param_index,
param_desc,
test.status_comment);
param_test.status_comment);
kunit_update_stats(&param_stats, test.status);
kunit_update_stats(&param_stats, param_test.status);
/* Get next param. */
param_desc[0] = '\0';
test.param_value = test_case->generate_params(test.param_value, param_desc);
test.param_index++;
test.status = KUNIT_SUCCESS;
test.status_comment[0] = '\0';
test.priv = NULL;
curr_param = test_case->generate_params(&test, curr_param,
param_desc);
}
/*
* TODO: Put into a try catch. Since we don't need suite->exit
* for it we can't reuse kunit_try_run_cleanup for this yet.
*/
if (test_case->param_exit)
test_case->param_exit(&test);
/* TODO: Put this kunit_cleanup into a try-catch. */
kunit_cleanup(&test);
}
test_case_end:
kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
kunit_print_test_stats(&test, param_stats);

View File

@ -210,6 +210,8 @@ pub const fn kunit_case(
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
module_name: core::ptr::null_mut(),
log: core::ptr::null_mut(),
param_init: None,
param_exit: None,
}
}
@ -229,6 +231,8 @@ pub const fn kunit_case_null() -> kernel::bindings::kunit_case {
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
module_name: core::ptr::null_mut(),
log: core::ptr::null_mut(),
param_init: None,
param_exit: None,
}
}
@ -357,4 +361,11 @@ mod tests {
fn rust_test_kunit_in_kunit_test() {
assert!(in_kunit_test());
}
#[test]
#[cfg(not(all()))]
fn rust_test_kunit_always_disabled_test() {
// This test should never run because of the `cfg`.
assert!(false);
}
}

View File

@ -5,6 +5,7 @@
//! Copyright (c) 2023 José Expósito <jose.exposito89@gmail.com>
use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
use std::collections::HashMap;
use std::fmt::Write;
pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
@ -41,20 +42,32 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
// Get the functions set as tests. Search for `[test]` -> `fn`.
let mut body_it = body.stream().into_iter();
let mut tests = Vec::new();
let mut attributes: HashMap<String, TokenStream> = HashMap::new();
while let Some(token) = body_it.next() {
match token {
TokenTree::Group(ident) if ident.to_string() == "[test]" => match body_it.next() {
Some(TokenTree::Ident(ident)) if ident.to_string() == "fn" => {
let test_name = match body_it.next() {
Some(TokenTree::Ident(ident)) => ident.to_string(),
_ => continue,
};
tests.push(test_name);
TokenTree::Punct(ref p) if p.as_char() == '#' => match body_it.next() {
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => {
if let Some(TokenTree::Ident(name)) = g.stream().into_iter().next() {
// Collect attributes because we need to find which are tests. We also
// need to copy `cfg` attributes so tests can be conditionally enabled.
attributes
.entry(name.to_string())
.or_default()
.extend([token, TokenTree::Group(g)]);
}
continue;
}
_ => continue,
_ => (),
},
TokenTree::Ident(i) if i.to_string() == "fn" && attributes.contains_key("test") => {
if let Some(TokenTree::Ident(test_name)) = body_it.next() {
tests.push((test_name, attributes.remove("cfg").unwrap_or_default()))
}
}
_ => (),
}
attributes.clear();
}
// Add `#[cfg(CONFIG_KUNIT="y")]` before the module declaration.
@ -100,11 +113,22 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
let mut test_cases = "".to_owned();
let mut assert_macros = "".to_owned();
let path = crate::helpers::file();
for test in &tests {
let num_tests = tests.len();
for (test, cfg_attr) in tests {
let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{test}");
// An extra `use` is used here to reduce the length of the message.
// Append any `cfg` attributes the user might have written on their tests so we don't
// attempt to call them when they are `cfg`'d out. An extra `use` is used here to reduce
// the length of the assert message.
let kunit_wrapper = format!(
"unsafe extern \"C\" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) {{ use ::kernel::kunit::is_test_result_ok; assert!(is_test_result_ok({test}())); }}",
r#"unsafe extern "C" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit)
{{
(*_test).status = ::kernel::bindings::kunit_status_KUNIT_SKIPPED;
{cfg_attr} {{
(*_test).status = ::kernel::bindings::kunit_status_KUNIT_SUCCESS;
use ::kernel::kunit::is_test_result_ok;
assert!(is_test_result_ok({test}()));
}}
}}"#,
);
writeln!(kunit_macros, "{kunit_wrapper}").unwrap();
writeln!(
@ -139,7 +163,7 @@ macro_rules! assert_eq {{
writeln!(
kunit_macros,
"static mut TEST_CASES: [::kernel::bindings::kunit_case; {}] = [\n{test_cases} ::kernel::kunit::kunit_case_null(),\n];",
tests.len() + 1
num_tests + 1
)
.unwrap();

View File

@ -1,8 +1,7 @@
# Config options which are added to UML builds by default
# Enable virtio/pci, as a lot of tests require it.
CONFIG_VIRTIO_UML=y
CONFIG_UML_PCI_OVER_VIRTIO=y
# Enable pci, as a lot of tests require it.
CONFIG_KUNIT_UML_PCI=y
# Enable FORTIFY_SOURCE for wider checking.
CONFIG_FORTIFY_SOURCE=y

View File

@ -228,7 +228,7 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
fake_test.counts.passed = 1
output: Iterable[str] = input_data
if request.raw_output == 'all':
if request.raw_output == 'all' or request.raw_output == 'full':
pass
elif request.raw_output == 'kunit':
output = kunit_parser.extract_tap_lines(output)
@ -425,7 +425,7 @@ def add_parse_opts(parser: argparse.ArgumentParser) -> None:
parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
'By default, filters to just KUnit output. Use '
'--raw_output=all to show everything',
type=str, nargs='?', const='all', default=None, choices=['all', 'kunit'])
type=str, nargs='?', const='all', default=None, choices=['all', 'full', 'kunit'])
parser.add_argument('--json',
nargs='?',
help='Prints parsed test results as JSON to stdout or a file if '

View File

@ -352,9 +352,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
lines.pop()
return True
TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$')
TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$')
TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$')
TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$')
def peek_test_name_match(lines: LineStream, test: Test) -> bool:
"""
@ -379,6 +379,8 @@ def peek_test_name_match(lines: LineStream, test: Test) -> bool:
if not match:
return False
name = match.group(4)
if not name:
return False
return name == test.name
def parse_test_result(lines: LineStream, test: Test,
@ -416,7 +418,7 @@ def parse_test_result(lines: LineStream, test: Test,
# Set name of test object
if skip_match:
test.name = skip_match.group(4)
test.name = skip_match.group(4) or skip_match.group(5)
else:
test.name = match.group(4)

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
from ..qemu_config import QemuArchParams
QEMU_ARCH = QemuArchParams(linux_arch='mips',
kconfig='''
CONFIG_32BIT=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_MIPS_MALTA=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
''',
qemu_arch='mips',
kernel_path='vmlinuz',
kernel_command_line='console=ttyS0',
extra_qemu_params=['-M', 'malta'])

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0
from ..qemu_config import QemuArchParams
QEMU_ARCH = QemuArchParams(linux_arch='mips',
kconfig='''
CONFIG_CPU_MIPS64_R2=y
CONFIG_64BIT=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_MIPS_MALTA=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
''',
qemu_arch='mips64',
kernel_path='vmlinuz',
kernel_command_line='console=ttyS0',
extra_qemu_params=['-M', 'malta', '-cpu', '5KEc'])

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0
from ..qemu_config import QemuArchParams
QEMU_ARCH = QemuArchParams(linux_arch='mips',
kconfig='''
CONFIG_CPU_MIPS64_R2=y
CONFIG_64BIT=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MIPS_MALTA=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
''',
qemu_arch='mips64el',
kernel_path='vmlinuz',
kernel_command_line='console=ttyS0',
extra_qemu_params=['-M', 'malta', '-cpu', '5KEc'])

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
from ..qemu_config import QemuArchParams
QEMU_ARCH = QemuArchParams(linux_arch='mips',
kconfig='''
CONFIG_32BIT=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MIPS_MALTA=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
''',
qemu_arch='mipsel',
kernel_path='vmlinuz',
kernel_command_line='console=ttyS0',
extra_qemu_params=['-M', 'malta'])

View File

@ -1,5 +1,5 @@
TAP version 13
1..2
1..3
# selftests: membarrier: membarrier_test_single_thread
# TAP version 13
# 1..2
@ -12,3 +12,4 @@ ok 1 selftests: membarrier: membarrier_test_single_thread
# ok 1 sys_membarrier available
# ok 2 sys membarrier invalid command test: command = -1, flags = 0, errno = 22. Failed as expected
ok 2 selftests: membarrier: membarrier_test_multi_thread
ok 3 # SKIP selftests: membarrier: membarrier_test_multi_thread