On 21.07.2025 11:43, Oleksii Kurochko wrote:
> On 7/2/25 1:44 PM, Jan Beulich wrote:
>> On 10.06.2025 15:05, Oleksii Kurochko wrote:
>>> --- a/xen/arch/riscv/p2m.c
>>> +++ b/xen/arch/riscv/p2m.c
>>> @@ -1055,3 +1055,134 @@ int guest_physmap_add_entry(struct domain *d,
>>>   {
>>>       return p2m_insert_mapping(d, gfn, (1 << page_order), mfn, t);
>>>   }
>>> +
>>> +/*
>>> + * Get the details of a given gfn.
>>> + *
>>> + * If the entry is present, the associated MFN will be returned and the
>>> + * access and type filled up. The page_order will correspond to the
>> You removed p2m_access_t * from the parameters; you need to also update
>> the comment then accordingly.
>>
>>> + * order of the mapping in the page table (i.e it could be a superpage).
>>> + *
>>> + * If the entry is not present, INVALID_MFN will be returned and the
>>> + * page_order will be set according to the order of the invalid range.
>>> + *
>>> + * valid will contain the value of bit[0] (e.g valid bit) of the
>>> + * entry.
>>> + */
>>> +static mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
>>> +                           p2m_type_t *t,
>>> +                           unsigned int *page_order,
>>> +                           bool *valid)
>>> +{
>>> +    paddr_t addr = gfn_to_gaddr(gfn);
>>> +    unsigned int level = 0;
>>> +    pte_t entry, *table;
>>> +    int rc;
>>> +    mfn_t mfn = INVALID_MFN;
>>> +    p2m_type_t _t;
>> Please no local variables with leading underscores. In x86 we commonly
>> name such variables p2mt.
>>
>>> +    DECLARE_OFFSETS(offsets, addr);
>> This is the sole use of "addr". Is such a local variable really worth having?
> 
> Not really, I'll drop it.
> 
>>> +    ASSERT(p2m_is_locked(p2m));
>>> +    BUILD_BUG_ON(XEN_PT_LEVEL_MAP_MASK(0) != PAGE_MASK);
>>> +
>>> +    /* Allow t to be NULL */
>>> +    t = t ?: &_t;
>>> +
>>> +    *t = p2m_invalid;
>>> +
>>> +    if ( valid )
>>> +        *valid = false;
>>> +
>>> +    /* XXX: Check if the mapping is lower than the mapped gfn */
>>> +
>>> +    /* This gfn is higher than the highest the p2m map currently holds */
>>> +    if ( gfn_x(gfn) > gfn_x(p2m->max_mapped_gfn) )
>>> +    {
>>> +        for ( level = P2M_ROOT_LEVEL; level ; level-- )
>> Nit: Stray blank before the 2nd semicolon. (Again at least once below.)
>>
>>> +            if ( (gfn_x(gfn) & (XEN_PT_LEVEL_MASK(level) >> PAGE_SHIFT)) >
>>> +                 gfn_x(p2m->max_mapped_gfn) )
>>> +                break;
>>> +
>>> +        goto out;
>>> +    }
>>> +
>>> +    table = p2m_get_root_pointer(p2m, gfn);
>>> +
>>> +    /*
>>> +     * the table should always be non-NULL because the gfn is below
>>> +     * p2m->max_mapped_gfn and the root table pages are always present.
>>> +     */
>>> +    if ( !table )
>>> +    {
>>> +        ASSERT_UNREACHABLE();
>>> +        level = P2M_ROOT_LEVEL;
>>> +        goto out;
>>> +    }
>>> +
>>> +    for ( level = P2M_ROOT_LEVEL; level ; level-- )
>>> +    {
>>> +        rc = p2m_next_level(p2m, true, level, &table, offsets[level]);
>>> +        if ( (rc == GUEST_TABLE_MAP_NONE) && (rc != GUEST_TABLE_MAP_NOMEM) 
>>> )
>> This condition looks odd. As written the rhs of the && is redundant.
> 
> And it is wrong. It should:
>   if ( (rc == P2M_TABLE_MAP_NONE) || (rc == P2M_TABLE_MAP_NOMEM) )
> 
>>> +            goto out_unmap;
>>> +        else if ( rc != GUEST_TABLE_NORMAL )
>> As before, no real need for "else" in such cases.
>>
>>> +            break;
>>> +    }
>>> +
>>> +    entry = table[offsets[level]];
>>> +
>>> +    if ( p2me_is_valid(p2m, entry) )
>>> +    {
>>> +        *t = p2m_type_radix_get(p2m, entry);
>> If the incoming argument is NULL, the somewhat expensive radix tree lookup
>> is unnecessary here.
> 
> Good point.
> 
>>> +        mfn = pte_get_mfn(entry);
>>> +        /*
>>> +         * The entry may point to a superpage. Find the MFN associated
>>> +         * to the GFN.
>>> +         */
>>> +        mfn = mfn_add(mfn,
>>> +                      gfn_x(gfn) & (BIT(XEN_PT_LEVEL_ORDER(level), UL) - 
>>> 1));
>>> +
>>> +        if ( valid )
>>> +            *valid = pte_is_valid(entry);
>> Interesting. Why not the P2M counterpart of the function? Yes, the comment
>> ahead of the function says so, but I don't see why the valid bit suddenly
>> is relevant here (besides the P2M type).
> 
> This valid variable is expected to be used in the caller (something what Arm 
> does here
> https://gitlab.com/xen-project/xen/-/blob/staging/xen/arch/arm/p2m.c#L375) to 
> check if
> it is needed to do flush_page_to_ram(), so if the the valid bit in PTE was 
> set to 0
> then it means nothing should be flushed as entry wasn't used as it marked 
> invalid.

I hope you see what a mess you get if you have two flavors of "valid" for a
PTE.

>>> +    }
>>> +
>>> +out_unmap:
>>> +    unmap_domain_page(table);
>>> +
>>> +out:
>> Nit: Style (bot labels).
>>
>>> +    if ( page_order )
>>> +        *page_order = XEN_PT_LEVEL_ORDER(level);
>>> +
>>> +    return mfn;
>>> +}
>>> +
>>> +static mfn_t p2m_lookup(struct domain *d, gfn_t gfn, p2m_type_t *t)
>> pointer-to-const for the 1st arg? But again more likely struct p2m_domain *
>> anyway?
> 
> |struct p2_domain| would be better, but I’m not really sure that a
> pointer-to-const can be used here.

Note how I also didn't suggest const there.

> I expect that, in that case,
> |p2m_read_lock()| would also need to accept a pointer-to-const, and since it
> calls|read_lock()| internally, that could be a problem because|read_lock() 
> |accepts a|rwlock_t *l|.

Correct.

Jan

Reply via email to