Hi Jason,
On Mon, Jun 16, 2025 at 03:06:04PM -0300, Jason Gunthorpe wrote:
The generic API is intended to be separated from the implementation of page table algorithms. It contains only accessors for walking and manipulating the table and helpers that are useful for building an implementation. Memory management is not in the generic API, but part of the implementation.
Using a multi-compilation approach the implementation module would include headers in this order:
common.h defs_FMT.h pt_defs.h FMT.h pt_common.h IMPLEMENTATION.h
Where each compilation unit would have a combination of FMT and IMPLEMENTATION to produce a per-format per-implementation module.
The API is designed so that the format headers have minimal logic, and default implementations are provided if the format doesn't include one.
Generally formats provide their code via an inline function using the pattern:
static inline FMTpt_XX(..) {} #define pt_XX FMTpt_XX
The common code then enforces a function signature so that there is no drift in function arguments, or accidental polymorphic functions (as has been slightly troublesome in mm). Use of function-like #defines are avoided in the format even though many of the functions are small enough.
Provide kdocs for the API surface.
This is enough to implement the 8 initial format variations with all of their features:
- Entries comprised of contiguous blocks of IO PTEs for larger page sizes (AMDv1, ARMv8)
- Multi-level tables, up to 6 levels. Runtime selected top level
- Runtime variable table level size (ARM's concatenated tables)
- Expandable top level (AMDv1)
- Optional leaf entries at any level
- 32 bit/64 bit virtual and output addresses, using every bit
- Sign extended addressing (x86)
- Dirty tracking
A basic simple format takes about 200 lines to declare the require inline functions.
Tested-by: Alejandro Jimenez alejandro.j.jimenez@oracle.com Signed-off-by: Jason Gunthorpe jgg@nvidia.com
../..
+static __always_inline struct pt_range _pt_top_range(struct pt_common *common,
uintptr_t top_of_table)
+{
- struct pt_range range = {
.common = common,
.top_table =
(struct pt_table_p *)(top_of_table &
~(uintptr_t)PT_TOP_LEVEL_MASK),
+#ifdef PT_FIXED_TOP_LEVEL
I am not able to find definition for above macro. Was it intentional to leave the macro 'PT_FIXED_TOP_LEVEL' undefined?
Thanks, Ankit
.top_level = PT_FIXED_TOP_LEVEL,
+#else
.top_level = top_of_table % (1 << PT_TOP_LEVEL_BITS),
+#endif
- };
- struct pt_state pts = { .range = &range, .level = range.top_level };
- unsigned int max_vasz_lg2;
- max_vasz_lg2 = common->max_vasz_lg2;
- if (pt_feature(common, PT_FEAT_DYNAMIC_TOP) &&
pts.level != PT_MAX_TOP_LEVEL)
max_vasz_lg2 = min_t(unsigned int, common->max_vasz_lg2,
pt_num_items_lg2(&pts) +
pt_table_item_lg2sz(&pts));
- /*
* The top range will default to the lower region only with sign extend.
*/
- range.max_vasz_lg2 = max_vasz_lg2;
- if (pt_feature(common, PT_FEAT_SIGN_EXTEND))
max_vasz_lg2--;
- range.va = fvalog2_set_mod(pt_full_va_prefix(common), 0, max_vasz_lg2);
- range.last_va =
fvalog2_set_mod_max(pt_full_va_prefix(common), max_vasz_lg2);
- return range;
+}
2.43.0