108 lines
4.1 KiB
Plaintext
108 lines
4.1 KiB
Plaintext
|
==================
|
||
|
Memblock simulator
|
||
|
==================
|
||
|
|
||
|
Introduction
|
||
|
============
|
||
|
|
||
|
Memblock is a boot time memory allocator[1] that manages memory regions before
|
||
|
the actual memory management is initialized. Its APIs allow to register physical
|
||
|
memory regions, mark them as available or reserved, allocate a block of memory
|
||
|
within the requested range and/or in specific NUMA node, and many more.
|
||
|
|
||
|
Because it is used so early in the booting process, testing and debugging it is
|
||
|
difficult. This test suite, usually referred as memblock simulator, is
|
||
|
an attempt at testing the memblock mechanism. It runs one monolithic test that
|
||
|
consist of a series of checks that exercise both the basic operations and
|
||
|
allocation functionalities of memblock. The main data structure of the boot time
|
||
|
memory allocator is initialized at the build time, so the checks here reuse its
|
||
|
instance throughout the duration of the test. To ensure that tests don't affect
|
||
|
each other, region arrays are reset in between.
|
||
|
|
||
|
As this project uses the actual memblock code and has to run in user space,
|
||
|
some of the kernel definitions were stubbed by the initial commit that
|
||
|
introduced memblock simulator (commit 16802e55dea9 ("memblock tests: Add
|
||
|
skeleton of the memblock simulator")) and a few preparation commits just
|
||
|
before it. Most of them don't match the kernel implementation, so one should
|
||
|
consult them first before making any significant changes to the project.
|
||
|
|
||
|
Usage
|
||
|
=====
|
||
|
|
||
|
To run the tests, build the main target and run it:
|
||
|
|
||
|
$ make && ./main
|
||
|
|
||
|
A successful run produces no output. It is also possible to override different
|
||
|
configuration parameters. For example, to simulate enabled NUMA, use:
|
||
|
|
||
|
$ make NUMA=1
|
||
|
|
||
|
For the full list of options, see `make help`.
|
||
|
|
||
|
Project structure
|
||
|
=================
|
||
|
|
||
|
The project has one target, main, which calls a group of checks for basic and
|
||
|
allocation functions. Tests for each group are defined in dedicated files, as it
|
||
|
can be seen here:
|
||
|
|
||
|
memblock
|
||
|
|-- asm ------------------,
|
||
|
|-- lib |-- implement function and struct stubs
|
||
|
|-- linux ------------------'
|
||
|
|-- scripts
|
||
|
| |-- Makefile.include -- handles `make` parameters
|
||
|
|-- tests
|
||
|
| |-- alloc_api.(c|h) -- memblock_alloc tests
|
||
|
| |-- alloc_helpers_api.(c|h) -- memblock_alloc_from tests
|
||
|
| |-- alloc_nid_api.(c|h) -- memblock_alloc_try_nid tests
|
||
|
| |-- basic_api.(c|h) -- memblock_add/memblock_reserve/... tests
|
||
|
| |-- common.(c|h) -- helper functions for resetting memblock;
|
||
|
|-- main.c --------------. dummy physical memory definition
|
||
|
|-- Makefile `- test runner
|
||
|
|-- README
|
||
|
|-- TODO
|
||
|
|-- .gitignore
|
||
|
|
||
|
Simulating physical memory
|
||
|
==========================
|
||
|
|
||
|
Some allocation functions clear the memory in the process, so it is required for
|
||
|
memblock to track valid memory ranges. To achieve this, the test suite registers
|
||
|
with memblock memory stored by test_memory struct. It is a small wrapper that
|
||
|
points to a block of memory allocated via malloc. For each group of allocation
|
||
|
tests, dummy physical memory is allocated, added to memblock, and then released
|
||
|
at the end of the test run. The structure of a test runner checking allocation
|
||
|
functions is as follows:
|
||
|
|
||
|
int memblock_alloc_foo_checks(void)
|
||
|
{
|
||
|
reset_memblock_attributes(); /* data structure reset */
|
||
|
dummy_physical_memory_init(); /* allocate and register memory */
|
||
|
|
||
|
(...allocation checks...)
|
||
|
|
||
|
dummy_physical_memory_cleanup(); /* free the memory */
|
||
|
}
|
||
|
|
||
|
There's no need to explicitly free the dummy memory from memblock via
|
||
|
memblock_free() call. The entry will be erased by reset_memblock_regions(),
|
||
|
called at the beginning of each test.
|
||
|
|
||
|
Known issues
|
||
|
============
|
||
|
|
||
|
1. Requesting a specific NUMA node via memblock_alloc_node() does not work as
|
||
|
intended. Once the fix is in place, tests for this function can be added.
|
||
|
|
||
|
2. Tests for memblock_alloc_low() can't be easily implemented. The function uses
|
||
|
ARCH_LOW_ADDRESS_LIMIT marco, which can't be changed to point at the low
|
||
|
memory of the memory_block.
|
||
|
|
||
|
References
|
||
|
==========
|
||
|
|
||
|
1. Boot time memory management documentation page:
|
||
|
https://www.kernel.org/doc/html/latest/core-api/boot-time-mm.html
|