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
> 

Reply via email to