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 <[email protected]>
> Signed-off-by: Jason Gunthorpe <[email protected]>
> ---
../..
> +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
>