diff mbox series

[v7,1/3] x86/tlb: introduce a flush HVM ASIDs flag

Message ID 20200319154716.34556-2-roger.pau@citrix.com (mailing list archive)
State Superseded
Headers show
Series x86/guest: use assisted TLB flush in guest mode | expand

Commit Message

Roger Pau Monné March 19, 2020, 3:47 p.m. UTC
Introduce a specific flag to request a HVM guest linear TLB flush,
which is an ASID/VPID tickle that forces a guest linear to guest
physical TLB flush for all HVM guests.

This was previously unconditionally done in each pre_flush call, but
that's not required: HVM guests not using shadow don't require linear
TLB flushes as Xen doesn't modify the guest page tables in that case
(ie: when using HAP). Note that shadow paging code already takes care
of issuing the necessary flushes when the shadow page tables are
modified.

In order to keep the previous behavior modify all shadow code TLB
flushes to also flush the guest linear to physical TLB. I haven't
looked at each specific shadow code TLB flush in order to figure out
whether it actually requires a guest TLB flush or not, so there might
be room for improvement in that regard.

Also perform ASID/VPIT flushes when modifying the p2m tables as it's a
requirement for AMD hardware. Finally keep the flush in
switch_cr3_cr4, as it's not clear whether code could rely on
switch_cr3_cr4 also performing a guest linear TLB flush. A following
patch can remove the ASID/VPIT tickle from switch_cr3_cr4 if found to
not be necessary.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v6:
 - Add ASID/VPIT flushes when modifying the p2m.
 - Keep the ASID/VPIT flush in switch_cr3_cr4.

Changes since v5:
 - Rename FLUSH_GUESTS_TLB to FLUSH_HVM_ASID_CORE.
 - Clarify commit message.
 - Define FLUSH_HVM_ASID_CORE to 0 when !CONFIG_HVM.
---
 xen/arch/x86/flushtlb.c          |  6 ++++--
 xen/arch/x86/mm/hap/hap.c        |  8 ++++----
 xen/arch/x86/mm/hap/nested_hap.c |  2 +-
 xen/arch/x86/mm/p2m-pt.c         |  3 ++-
 xen/arch/x86/mm/paging.c         |  2 +-
 xen/arch/x86/mm/shadow/common.c  | 18 +++++++++---------
 xen/arch/x86/mm/shadow/hvm.c     |  2 +-
 xen/arch/x86/mm/shadow/multi.c   | 16 ++++++++--------
 xen/include/asm-x86/flushtlb.h   |  6 ++++++
 xen/include/xen/mm.h             |  2 +-
 10 files changed, 37 insertions(+), 28 deletions(-)

Comments

Julien Grall March 19, 2020, 4:21 p.m. UTC | #1
Hi,

On 19/03/2020 15:47, Roger Pau Monne wrote:
> diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
> index d0d095d9c7..02aad43042 100644
> --- a/xen/include/xen/mm.h
> +++ b/xen/include/xen/mm.h
> @@ -644,7 +644,7 @@ static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
>       if ( !cpumask_empty(&mask) )
>       {
>           perfc_incr(need_flush_tlb_flush);
> -        flush_tlb_mask(&mask);
> +        flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);

A rule of thumb is any modification in common code may impact Arm. This 
is a case here because the flag and the "new" function are not defined 
on Arm and therefore going to break the build.

Why can't you keep flush_tlb_mask() here?

Cheers,
Roger Pau Monné March 19, 2020, 5:38 p.m. UTC | #2
On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> Hi,
> 
> On 19/03/2020 15:47, Roger Pau Monne wrote:
> > diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
> > index d0d095d9c7..02aad43042 100644
> > --- a/xen/include/xen/mm.h
> > +++ b/xen/include/xen/mm.h
> > @@ -644,7 +644,7 @@ static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
> >       if ( !cpumask_empty(&mask) )
> >       {
> >           perfc_incr(need_flush_tlb_flush);
> > -        flush_tlb_mask(&mask);
> > +        flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
> 
> A rule of thumb is any modification in common code may impact Arm. This is a
> case here because the flag and the "new" function are not defined on Arm and
> therefore going to break the build.

flush_mask is not a new function, it's just not implemented on ARM I
guess.

> Why can't you keep flush_tlb_mask() here?

Because filtered_flush_tlb_mask is used in populate_physmap, and
changes to the phymap require an ASID flush on AMD hardware.

I will send an updated version.

Thanks, Roger.
Julien Grall March 19, 2020, 6:07 p.m. UTC | #3
On 19/03/2020 17:38, Roger Pau Monné wrote:
> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>> Hi,
>>
>> On 19/03/2020 15:47, Roger Pau Monne wrote:
>>> diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
>>> index d0d095d9c7..02aad43042 100644
>>> --- a/xen/include/xen/mm.h
>>> +++ b/xen/include/xen/mm.h
>>> @@ -644,7 +644,7 @@ static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
>>>        if ( !cpumask_empty(&mask) )
>>>        {
>>>            perfc_incr(need_flush_tlb_flush);
>>> -        flush_tlb_mask(&mask);
>>> +        flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
>>
>> A rule of thumb is any modification in common code may impact Arm. This is a
>> case here because the flag and the "new" function are not defined on Arm and
>> therefore going to break the build.
> 
> flush_mask is not a new function, it's just not implemented on ARM I
> guess.

That's why I said it in "" ;).

>  >> Why can't you keep flush_tlb_mask() here?
> 
> Because filtered_flush_tlb_mask is used in populate_physmap, and
> changes to the phymap require an ASID flush on AMD hardware.

I am afraid this does not yet explain me why flush_tlb_mask() could not 
be updated so it flush the ASID on AMD hardware.

This would actually match the behavior of flush_tlb_mask() on Arm where 
all the guest TLBs would be removed.

Cheers,
Roger Pau Monné March 19, 2020, 6:43 p.m. UTC | #4
On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> 
> 
> On 19/03/2020 17:38, Roger Pau Monné wrote:
> > On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> >  >> Why can't you keep flush_tlb_mask() here?
> > 
> > Because filtered_flush_tlb_mask is used in populate_physmap, and
> > changes to the phymap require an ASID flush on AMD hardware.
> 
> I am afraid this does not yet explain me why flush_tlb_mask() could not be
> updated so it flush the ASID on AMD hardware.

Current behavior previous to this patch is to flush the ASIDs on
every TLB flush.

flush_tlb_mask is too widely used on x86 in places where there's no
need to flush the ASIDs. This prevents using assisted flushes (by L0)
when running nested, since those assisted flushes performed by L0
don't flush the L2 guests TLBs.

I could keep current behavior and leave flush_tlb_mask also flushing the
ASIDs, but that seems wrong as the function doesn't have anything in
it's name that suggests it also flushes the in-guest TLBs for HVM.

I would rather prefer the default to be to not flush the
ASIDs, so that users need to specify so by passing the flag to
flusk_mask.

> This would actually match the behavior of flush_tlb_mask() on Arm where all
> the guest TLBs would be removed.

That's how it used to be previous to this patch, and the whole point
is to split the ASID flushes into a separate flag, so it's not done
for every TLB flush.

Thanks, Roger.
Julien Grall March 19, 2020, 7:07 p.m. UTC | #5
Hi,

On 19/03/2020 18:43, Roger Pau Monné wrote:
> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>
>>
>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>   >> Why can't you keep flush_tlb_mask() here?
>>>
>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>> changes to the phymap require an ASID flush on AMD hardware.
>>
>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>> updated so it flush the ASID on AMD hardware.
> 
> Current behavior previous to this patch is to flush the ASIDs on
> every TLB flush.
> 
> flush_tlb_mask is too widely used on x86 in places where there's no
> need to flush the ASIDs. This prevents using assisted flushes (by L0)
> when running nested, since those assisted flushes performed by L0
> don't flush the L2 guests TLBs.
> 
> I could keep current behavior and leave flush_tlb_mask also flushing the
> ASIDs, but that seems wrong as the function doesn't have anything in
> it's name that suggests it also flushes the in-guest TLBs for HVM.

I agree the name is confusing, I had to look at the implementation to 
understand what it does.

How about renaming (or introducing) the function to 
flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?

> 
> I would rather prefer the default to be to not flush the
> ASIDs, so that users need to specify so by passing the flag to
> flusk_mask.
That's x86 choice. For common, I would rather no introduce those flags 
until we have another arch that make use of it.

> 
>> This would actually match the behavior of flush_tlb_mask() on Arm where all
>> the guest TLBs would be removed.
> 
> That's how it used to be previous to this patch, and the whole point
> is to split the ASID flushes into a separate flag, so it's not done
> for every TLB flush.

Well, tlb_flush_mask() is only implemented for the benefit of common 
code. It has no other users on Arm.

It feels to me that we want an helper that will nuke all the guest TLBs 
on a given set of CPUs (see above for some name suggestion).

On x86, you could implement it using flush_mask(). On Arm, this could be 
a rename of the existing function flush_tlb_mask().

Cheers,
Jan Beulich March 20, 2020, 7:21 a.m. UTC | #6
On 19.03.2020 20:07, Julien Grall wrote:
> Hi,
> 
> On 19/03/2020 18:43, Roger Pau Monné wrote:
>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>
>>>
>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>   >> Why can't you keep flush_tlb_mask() here?
>>>>
>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>
>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>> updated so it flush the ASID on AMD hardware.
>>
>> Current behavior previous to this patch is to flush the ASIDs on
>> every TLB flush.
>>
>> flush_tlb_mask is too widely used on x86 in places where there's no
>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>> when running nested, since those assisted flushes performed by L0
>> don't flush the L2 guests TLBs.
>>
>> I could keep current behavior and leave flush_tlb_mask also flushing the
>> ASIDs, but that seems wrong as the function doesn't have anything in
>> it's name that suggests it also flushes the in-guest TLBs for HVM.
> 
> I agree the name is confusing, I had to look at the implementation to understand what it does.
> 
> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?

And this would then flush _only_ guest TLBs?

>> I would rather prefer the default to be to not flush the
>> ASIDs, so that users need to specify so by passing the flag to
>> flusk_mask.
> That's x86 choice. For common, I would rather no introduce those flags until we have another arch that make use of it.

The flags should perhaps indeed remain x86-specific, but suitable
wrappers usable from common code should exist (as you suggest
below).

Jan

>>> This would actually match the behavior of flush_tlb_mask() on Arm where all
>>> the guest TLBs would be removed.
>>
>> That's how it used to be previous to this patch, and the whole point
>> is to split the ASID flushes into a separate flag, so it's not done
>> for every TLB flush.
> 
> Well, tlb_flush_mask() is only implemented for the benefit of common code. It has no other users on Arm.
> 
> It feels to me that we want an helper that will nuke all the guest TLBs on a given set of CPUs (see above for some name suggestion).
> 
> On x86, you could implement it using flush_mask(). On Arm, this could be a rename of the existing function flush_tlb_mask().
> 
> Cheers,
>
Roger Pau Monné March 20, 2020, 9:01 a.m. UTC | #7
On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> On 19.03.2020 20:07, Julien Grall wrote:
> > Hi,
> > 
> > On 19/03/2020 18:43, Roger Pau Monné wrote:
> >> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> >>>
> >>>
> >>> On 19/03/2020 17:38, Roger Pau Monné wrote:
> >>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> >>>>   >> Why can't you keep flush_tlb_mask() here?
> >>>>
> >>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
> >>>> changes to the phymap require an ASID flush on AMD hardware.
> >>>
> >>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
> >>> updated so it flush the ASID on AMD hardware.
> >>
> >> Current behavior previous to this patch is to flush the ASIDs on
> >> every TLB flush.
> >>
> >> flush_tlb_mask is too widely used on x86 in places where there's no
> >> need to flush the ASIDs. This prevents using assisted flushes (by L0)
> >> when running nested, since those assisted flushes performed by L0
> >> don't flush the L2 guests TLBs.
> >>
> >> I could keep current behavior and leave flush_tlb_mask also flushing the
> >> ASIDs, but that seems wrong as the function doesn't have anything in
> >> it's name that suggests it also flushes the in-guest TLBs for HVM.
> > 
> > I agree the name is confusing, I had to look at the implementation to understand what it does.
> > 
> > How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> 
> And this would then flush _only_ guest TLBs?

No, I think from Julien's proposal (if I understood it correctly)
flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
previous to this patch (flush Xen's TLBs + HVM ASIDs).

> >> I would rather prefer the default to be to not flush the
> >> ASIDs, so that users need to specify so by passing the flag to
> >> flusk_mask.
> > That's x86 choice. For common, I would rather no introduce those flags until we have another arch that make use of it.
> 
> The flags should perhaps indeed remain x86-specific, but suitable
> wrappers usable from common code should exist (as you suggest
> below).

I don't have a strong opinion re naming, are you OK with the names
proposed above?

Thanks, Roger.
Julien Grall March 20, 2020, 9:12 a.m. UTC | #8
Hi Roger,

On 20/03/2020 09:01, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>> On 19.03.2020 20:07, Julien Grall wrote:
>>> Hi,
>>>
>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>
>>>>>
>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>    >> Why can't you keep flush_tlb_mask() here?
>>>>>>
>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>
>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>> updated so it flush the ASID on AMD hardware.
>>>>
>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>> every TLB flush.
>>>>
>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>> when running nested, since those assisted flushes performed by L0
>>>> don't flush the L2 guests TLBs.
>>>>
>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>
>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>
>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>
>> And this would then flush _only_ guest TLBs?
> 
> No, I think from Julien's proposal (if I understood it correctly)
> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> previous to this patch (flush Xen's TLBs + HVM ASIDs).

It looks like there might be confusion on what "guest TLBs" means. In my 
view this means any TLBs associated directly or indirectly with the 
guest. On Arm, this would be nuke:
    - guest virtual address -> guest physical address TLB entry
    - guest physical address -> host physical address TLB entry
    - guest virtual address -> host physical address TLB entry

I would assume you want something similar on x86, right?

Cheers,
Roger Pau Monné March 20, 2020, 9:42 a.m. UTC | #9
On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
> Hi Roger,
> 
> On 20/03/2020 09:01, Roger Pau Monné wrote:
> > On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> > > On 19.03.2020 20:07, Julien Grall wrote:
> > > > Hi,
> > > > 
> > > > On 19/03/2020 18:43, Roger Pau Monné wrote:
> > > > > On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> > > > > > 
> > > > > > 
> > > > > > On 19/03/2020 17:38, Roger Pau Monné wrote:
> > > > > > > On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> > > > > > >    >> Why can't you keep flush_tlb_mask() here?
> > > > > > > 
> > > > > > > Because filtered_flush_tlb_mask is used in populate_physmap, and
> > > > > > > changes to the phymap require an ASID flush on AMD hardware.
> > > > > > 
> > > > > > I am afraid this does not yet explain me why flush_tlb_mask() could not be
> > > > > > updated so it flush the ASID on AMD hardware.
> > > > > 
> > > > > Current behavior previous to this patch is to flush the ASIDs on
> > > > > every TLB flush.
> > > > > 
> > > > > flush_tlb_mask is too widely used on x86 in places where there's no
> > > > > need to flush the ASIDs. This prevents using assisted flushes (by L0)
> > > > > when running nested, since those assisted flushes performed by L0
> > > > > don't flush the L2 guests TLBs.
> > > > > 
> > > > > I could keep current behavior and leave flush_tlb_mask also flushing the
> > > > > ASIDs, but that seems wrong as the function doesn't have anything in
> > > > > it's name that suggests it also flushes the in-guest TLBs for HVM.
> > > > 
> > > > I agree the name is confusing, I had to look at the implementation to understand what it does.
> > > > 
> > > > How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> > > 
> > > And this would then flush _only_ guest TLBs?
> > 
> > No, I think from Julien's proposal (if I understood it correctly)
> > flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> > previous to this patch (flush Xen's TLBs + HVM ASIDs).
> 
> It looks like there might be confusion on what "guest TLBs" means. In my
> view this means any TLBs associated directly or indirectly with the guest.
> On Arm, this would be nuke:
>    - guest virtual address -> guest physical address TLB entry
>    - guest physical address -> host physical address TLB entry
>    - guest virtual address -> host physical address TLB entry

AFAICT ASID flush on AMD hardware will flush any of the above, while
VPID flush on Intel will only flush the first item (guest linear to
guest physical). When using EPT on Intel you need to issue EPT flushes
when modifying the p2m, which will get rid of the last two types of
cached translations (guest-physical mappings and combined mappings in
Intel speak).

So the response is 'it depends' on whether the underlying hardware is
Intel or AMD. That's why the constant was renamed from
FLUSH_HVM_GUESTS_TLB to FLUSH_HVM_ASID_CORE.

Thanks, Roger.
Roger Pau Monné March 20, 2020, 10 a.m. UTC | #10
On Fri, Mar 20, 2020 at 10:42:14AM +0100, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
> > Hi Roger,
> > 
> > On 20/03/2020 09:01, Roger Pau Monné wrote:
> > > On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> > > > On 19.03.2020 20:07, Julien Grall wrote:
> > > > > Hi,
> > > > > 
> > > > > On 19/03/2020 18:43, Roger Pau Monné wrote:
> > > > > > On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> > > > > > > 
> > > > > > > 
> > > > > > > On 19/03/2020 17:38, Roger Pau Monné wrote:
> > > > > > > > On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> > > > > > > >    >> Why can't you keep flush_tlb_mask() here?
> > > > > > > > 
> > > > > > > > Because filtered_flush_tlb_mask is used in populate_physmap, and
> > > > > > > > changes to the phymap require an ASID flush on AMD hardware.
> > > > > > > 
> > > > > > > I am afraid this does not yet explain me why flush_tlb_mask() could not be
> > > > > > > updated so it flush the ASID on AMD hardware.
> > > > > > 
> > > > > > Current behavior previous to this patch is to flush the ASIDs on
> > > > > > every TLB flush.
> > > > > > 
> > > > > > flush_tlb_mask is too widely used on x86 in places where there's no
> > > > > > need to flush the ASIDs. This prevents using assisted flushes (by L0)
> > > > > > when running nested, since those assisted flushes performed by L0
> > > > > > don't flush the L2 guests TLBs.
> > > > > > 
> > > > > > I could keep current behavior and leave flush_tlb_mask also flushing the
> > > > > > ASIDs, but that seems wrong as the function doesn't have anything in
> > > > > > it's name that suggests it also flushes the in-guest TLBs for HVM.
> > > > > 
> > > > > I agree the name is confusing, I had to look at the implementation to understand what it does.
> > > > > 
> > > > > How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> > > > 
> > > > And this would then flush _only_ guest TLBs?
> > > 
> > > No, I think from Julien's proposal (if I understood it correctly)
> > > flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> > > previous to this patch (flush Xen's TLBs + HVM ASIDs).
> > 
> > It looks like there might be confusion on what "guest TLBs" means. In my
> > view this means any TLBs associated directly or indirectly with the guest.
> > On Arm, this would be nuke:
> >    - guest virtual address -> guest physical address TLB entry
> >    - guest physical address -> host physical address TLB entry
> >    - guest virtual address -> host physical address TLB entry
> 
> AFAICT ASID flush on AMD hardware will flush any of the above, while
> VPID flush on Intel will only flush the first item (guest linear to

Sorry, doing too many things at the same time. On Intel VPID flushes
will get rid of guest virtual to guest physical or host physical, but
not of guest physical to host physical, you need an EPT flush to
accomplish that.

Roger.
Julien Grall March 20, 2020, 10:08 a.m. UTC | #11
Hi,

On 20/03/2020 10:00, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 10:42:14AM +0100, Roger Pau Monné wrote:
>> On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
>>> Hi Roger,
>>>
>>> On 20/03/2020 09:01, Roger Pau Monné wrote:
>>>> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>>>>> On 19.03.2020 20:07, Julien Grall wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>>>>     >> Why can't you keep flush_tlb_mask() here?
>>>>>>>>>
>>>>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>>>>
>>>>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>>>>> updated so it flush the ASID on AMD hardware.
>>>>>>>
>>>>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>>>>> every TLB flush.
>>>>>>>
>>>>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>>>>> when running nested, since those assisted flushes performed by L0
>>>>>>> don't flush the L2 guests TLBs.
>>>>>>>
>>>>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>>>>
>>>>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>>>>
>>>>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>>>>
>>>>> And this would then flush _only_ guest TLBs?
>>>>
>>>> No, I think from Julien's proposal (if I understood it correctly)
>>>> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
>>>> previous to this patch (flush Xen's TLBs + HVM ASIDs).
>>>
>>> It looks like there might be confusion on what "guest TLBs" means. In my
>>> view this means any TLBs associated directly or indirectly with the guest.
>>> On Arm, this would be nuke:
>>>     - guest virtual address -> guest physical address TLB entry
>>>     - guest physical address -> host physical address TLB entry
>>>     - guest virtual address -> host physical address TLB entry
>>
>> AFAICT ASID flush on AMD hardware will flush any of the above, while
>> VPID flush on Intel will only flush the first item (guest linear to
> 
> Sorry, doing too many things at the same time. On Intel VPID flushes
> will get rid of guest virtual to guest physical or host physical, but
> not of guest physical to host physical, you need an EPT flush to
> accomplish that.
Are you suggesting that on x86, flush_tlb_mask() would not nuke the 
guest physical to host physical entries? If so, how is it meant to be safe?

Cheers,
Roger Pau Monné March 20, 2020, 10:24 a.m. UTC | #12
On Fri, Mar 20, 2020 at 10:08:33AM +0000, Julien Grall wrote:
> Hi,
> 
> On 20/03/2020 10:00, Roger Pau Monné wrote:
> > On Fri, Mar 20, 2020 at 10:42:14AM +0100, Roger Pau Monné wrote:
> > > On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
> > > > Hi Roger,
> > > > 
> > > > On 20/03/2020 09:01, Roger Pau Monné wrote:
> > > > > On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> > > > > > On 19.03.2020 20:07, Julien Grall wrote:
> > > > > > > Hi,
> > > > > > > 
> > > > > > > On 19/03/2020 18:43, Roger Pau Monné wrote:
> > > > > > > > On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > On 19/03/2020 17:38, Roger Pau Monné wrote:
> > > > > > > > > > On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> > > > > > > > > >     >> Why can't you keep flush_tlb_mask() here?
> > > > > > > > > > 
> > > > > > > > > > Because filtered_flush_tlb_mask is used in populate_physmap, and
> > > > > > > > > > changes to the phymap require an ASID flush on AMD hardware.
> > > > > > > > > 
> > > > > > > > > I am afraid this does not yet explain me why flush_tlb_mask() could not be
> > > > > > > > > updated so it flush the ASID on AMD hardware.
> > > > > > > > 
> > > > > > > > Current behavior previous to this patch is to flush the ASIDs on
> > > > > > > > every TLB flush.
> > > > > > > > 
> > > > > > > > flush_tlb_mask is too widely used on x86 in places where there's no
> > > > > > > > need to flush the ASIDs. This prevents using assisted flushes (by L0)
> > > > > > > > when running nested, since those assisted flushes performed by L0
> > > > > > > > don't flush the L2 guests TLBs.
> > > > > > > > 
> > > > > > > > I could keep current behavior and leave flush_tlb_mask also flushing the
> > > > > > > > ASIDs, but that seems wrong as the function doesn't have anything in
> > > > > > > > it's name that suggests it also flushes the in-guest TLBs for HVM.
> > > > > > > 
> > > > > > > I agree the name is confusing, I had to look at the implementation to understand what it does.
> > > > > > > 
> > > > > > > How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> > > > > > 
> > > > > > And this would then flush _only_ guest TLBs?
> > > > > 
> > > > > No, I think from Julien's proposal (if I understood it correctly)
> > > > > flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> > > > > previous to this patch (flush Xen's TLBs + HVM ASIDs).
> > > > 
> > > > It looks like there might be confusion on what "guest TLBs" means. In my
> > > > view this means any TLBs associated directly or indirectly with the guest.
> > > > On Arm, this would be nuke:
> > > >     - guest virtual address -> guest physical address TLB entry
> > > >     - guest physical address -> host physical address TLB entry
> > > >     - guest virtual address -> host physical address TLB entry
> > > 
> > > AFAICT ASID flush on AMD hardware will flush any of the above, while
> > > VPID flush on Intel will only flush the first item (guest linear to
> > 
> > Sorry, doing too many things at the same time. On Intel VPID flushes
> > will get rid of guest virtual to guest physical or host physical, but
> > not of guest physical to host physical, you need an EPT flush to
> > accomplish that.
> Are you suggesting that on x86, flush_tlb_mask() would not nuke the guest
> physical to host physical entries? If so, how is it meant to be safe?

You issue EPT flushes in that case when an EPT modification is
performed.

Thanks, Roger.
Julien Grall March 20, 2020, 10:36 a.m. UTC | #13
Hi,

On 20/03/2020 10:24, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 10:08:33AM +0000, Julien Grall wrote:
>> Hi,
>>
>> On 20/03/2020 10:00, Roger Pau Monné wrote:
>>> On Fri, Mar 20, 2020 at 10:42:14AM +0100, Roger Pau Monné wrote:
>>>> On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
>>>>> Hi Roger,
>>>>>
>>>>> On 20/03/2020 09:01, Roger Pau Monné wrote:
>>>>>> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>>>>>>> On 19.03.2020 20:07, Julien Grall wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>>>>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>>>>>>      >> Why can't you keep flush_tlb_mask() here?
>>>>>>>>>>>
>>>>>>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>>>>>>
>>>>>>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>>>>>>> updated so it flush the ASID on AMD hardware.
>>>>>>>>>
>>>>>>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>>>>>>> every TLB flush.
>>>>>>>>>
>>>>>>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>>>>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>>>>>>> when running nested, since those assisted flushes performed by L0
>>>>>>>>> don't flush the L2 guests TLBs.
>>>>>>>>>
>>>>>>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>>>>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>>>>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>>>>>>
>>>>>>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>>>>>>
>>>>>>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>>>>>>
>>>>>>> And this would then flush _only_ guest TLBs?
>>>>>>
>>>>>> No, I think from Julien's proposal (if I understood it correctly)
>>>>>> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
>>>>>> previous to this patch (flush Xen's TLBs + HVM ASIDs).
>>>>>
>>>>> It looks like there might be confusion on what "guest TLBs" means. In my
>>>>> view this means any TLBs associated directly or indirectly with the guest.
>>>>> On Arm, this would be nuke:
>>>>>      - guest virtual address -> guest physical address TLB entry
>>>>>      - guest physical address -> host physical address TLB entry
>>>>>      - guest virtual address -> host physical address TLB entry
>>>>
>>>> AFAICT ASID flush on AMD hardware will flush any of the above, while
>>>> VPID flush on Intel will only flush the first item (guest linear to
>>>
>>> Sorry, doing too many things at the same time. On Intel VPID flushes
>>> will get rid of guest virtual to guest physical or host physical, but
>>> not of guest physical to host physical, you need an EPT flush to
>>> accomplish that.
>> Are you suggesting that on x86, flush_tlb_mask() would not nuke the guest
>> physical to host physical entries? If so, how is it meant to be safe?
> 
> You issue EPT flushes in that case when an EPT modification is
> performed.

I am getting more and more confused with the goal of flush_tlb_mask() in 
common code.

Looking at the Arm code, the P2M code should already flush appropriatly 
the guest TLBs before giving back a page to the allocator.

So what are we trying to protect against with the call of flush_tlb_mask()?

Cheers,
Roger Pau Monné March 20, 2020, 11:18 a.m. UTC | #14
On Fri, Mar 20, 2020 at 10:36:49AM +0000, Julien Grall wrote:
> Hi,
> 
> On 20/03/2020 10:24, Roger Pau Monné wrote:
> > On Fri, Mar 20, 2020 at 10:08:33AM +0000, Julien Grall wrote:
> > > Hi,
> > > 
> > > On 20/03/2020 10:00, Roger Pau Monné wrote:
> > > > On Fri, Mar 20, 2020 at 10:42:14AM +0100, Roger Pau Monné wrote:
> > > > > On Fri, Mar 20, 2020 at 09:12:16AM +0000, Julien Grall wrote:
> > > > > > Hi Roger,
> > > > > > 
> > > > > > On 20/03/2020 09:01, Roger Pau Monné wrote:
> > > > > > > On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> > > > > > > > On 19.03.2020 20:07, Julien Grall wrote:
> > > > > > > > > Hi,
> > > > > > > > > 
> > > > > > > > > On 19/03/2020 18:43, Roger Pau Monné wrote:
> > > > > > > > > > On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > On 19/03/2020 17:38, Roger Pau Monné wrote:
> > > > > > > > > > > > On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> > > > > > > > > > > >      >> Why can't you keep flush_tlb_mask() here?
> > > > > > > > > > > > 
> > > > > > > > > > > > Because filtered_flush_tlb_mask is used in populate_physmap, and
> > > > > > > > > > > > changes to the phymap require an ASID flush on AMD hardware.
> > > > > > > > > > > 
> > > > > > > > > > > I am afraid this does not yet explain me why flush_tlb_mask() could not be
> > > > > > > > > > > updated so it flush the ASID on AMD hardware.
> > > > > > > > > > 
> > > > > > > > > > Current behavior previous to this patch is to flush the ASIDs on
> > > > > > > > > > every TLB flush.
> > > > > > > > > > 
> > > > > > > > > > flush_tlb_mask is too widely used on x86 in places where there's no
> > > > > > > > > > need to flush the ASIDs. This prevents using assisted flushes (by L0)
> > > > > > > > > > when running nested, since those assisted flushes performed by L0
> > > > > > > > > > don't flush the L2 guests TLBs.
> > > > > > > > > > 
> > > > > > > > > > I could keep current behavior and leave flush_tlb_mask also flushing the
> > > > > > > > > > ASIDs, but that seems wrong as the function doesn't have anything in
> > > > > > > > > > it's name that suggests it also flushes the in-guest TLBs for HVM.
> > > > > > > > > 
> > > > > > > > > I agree the name is confusing, I had to look at the implementation to understand what it does.
> > > > > > > > > 
> > > > > > > > > How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> > > > > > > > 
> > > > > > > > And this would then flush _only_ guest TLBs?
> > > > > > > 
> > > > > > > No, I think from Julien's proposal (if I understood it correctly)
> > > > > > > flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> > > > > > > previous to this patch (flush Xen's TLBs + HVM ASIDs).
> > > > > > 
> > > > > > It looks like there might be confusion on what "guest TLBs" means. In my
> > > > > > view this means any TLBs associated directly or indirectly with the guest.
> > > > > > On Arm, this would be nuke:
> > > > > >      - guest virtual address -> guest physical address TLB entry
> > > > > >      - guest physical address -> host physical address TLB entry
> > > > > >      - guest virtual address -> host physical address TLB entry
> > > > > 
> > > > > AFAICT ASID flush on AMD hardware will flush any of the above, while
> > > > > VPID flush on Intel will only flush the first item (guest linear to
> > > > 
> > > > Sorry, doing too many things at the same time. On Intel VPID flushes
> > > > will get rid of guest virtual to guest physical or host physical, but
> > > > not of guest physical to host physical, you need an EPT flush to
> > > > accomplish that.
> > > Are you suggesting that on x86, flush_tlb_mask() would not nuke the guest
> > > physical to host physical entries? If so, how is it meant to be safe?
> > 
> > You issue EPT flushes in that case when an EPT modification is
> > performed.
> 
> I am getting more and more confused with the goal of flush_tlb_mask() in
> common code.
> 
> Looking at the Arm code, the P2M code should already flush appropriatly the
> guest TLBs before giving back a page to the allocator.
> 
> So what are we trying to protect against with the call of flush_tlb_mask()?

So on x86 there are two completely different nested page table
technologies, NPT from AMD and EPT from Intel. EPT doesn't require a
VPID flush when modifying the nested page tables (it requires an EPT
flush), OTOH AMD NPT requires an ASID flush when modifying the tables,
and this seems to be implemented in common code for populate_physmap.

On x86 populate_physmap could also get rid of the flush, since the NPT
code already performs an ASID flush when modifying a nested page table
entry, but that's part of another patch.

Thanks, Roger.
Jan Beulich March 20, 2020, 1:16 p.m. UTC | #15
On 20.03.2020 10:01, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>> On 19.03.2020 20:07, Julien Grall wrote:
>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>
>>>>>
>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>   >> Why can't you keep flush_tlb_mask() here?
>>>>>>
>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>
>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>> updated so it flush the ASID on AMD hardware.
>>>>
>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>> every TLB flush.
>>>>
>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>> when running nested, since those assisted flushes performed by L0
>>>> don't flush the L2 guests TLBs.
>>>>
>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>
>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>
>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>
>> And this would then flush _only_ guest TLBs?
> 
> No, I think from Julien's proposal (if I understood it correctly)
> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> previous to this patch (flush Xen's TLBs + HVM ASIDs).
> 
>>>> I would rather prefer the default to be to not flush the
>>>> ASIDs, so that users need to specify so by passing the flag to
>>>> flusk_mask.
>>> That's x86 choice. For common, I would rather no introduce those flags until we have another arch that make use of it.
>>
>> The flags should perhaps indeed remain x86-specific, but suitable
>> wrappers usable from common code should exist (as you suggest
>> below).
> 
> I don't have a strong opinion re naming, are you OK with the names
> proposed above?

Well, no - imo a function named e.g. flush_tlb_all_guests_cpumask() is
not supposed to flush any host TLBs. But I'll also reply to Julien's
subsequent reply in a minute.

Jan
Jan Beulich March 20, 2020, 1:19 p.m. UTC | #16
On 20.03.2020 10:12, Julien Grall wrote:
> On 20/03/2020 09:01, Roger Pau Monné wrote:
>> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>>> On 19.03.2020 20:07, Julien Grall wrote:
>>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>>    >> Why can't you keep flush_tlb_mask() here?
>>>>>>>
>>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>>
>>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>>> updated so it flush the ASID on AMD hardware.
>>>>>
>>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>>> every TLB flush.
>>>>>
>>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>>> when running nested, since those assisted flushes performed by L0
>>>>> don't flush the L2 guests TLBs.
>>>>>
>>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>>
>>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>>
>>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>>
>>> And this would then flush _only_ guest TLBs?
>>
>> No, I think from Julien's proposal (if I understood it correctly)
>> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
>> previous to this patch (flush Xen's TLBs + HVM ASIDs).
> 
> It looks like there might be confusion on what "guest TLBs" means. In my view this means any TLBs associated directly or indirectly with the guest. On Arm, this would be nuke:
>    - guest virtual address -> guest physical address TLB entry
>    - guest physical address -> host physical address TLB entry
>    - guest virtual address -> host physical address TLB entry
> 
> I would assume you want something similar on x86, right?

I don't think we'd want the middle of the three items you list,
but I also don't see how this would be relevant here - flushing
that is a p2m operation, not one affecting in-guest translations.

Jan
Julien Grall March 20, 2020, 2:17 p.m. UTC | #17
Hi,

On 20/03/2020 13:19, Jan Beulich wrote:
> On 20.03.2020 10:12, Julien Grall wrote:
>> On 20/03/2020 09:01, Roger Pau Monné wrote:
>>> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>>>> On 19.03.2020 20:07, Julien Grall wrote:
>>>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>>>     >> Why can't you keep flush_tlb_mask() here?
>>>>>>>>
>>>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>>>
>>>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>>>> updated so it flush the ASID on AMD hardware.
>>>>>>
>>>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>>>> every TLB flush.
>>>>>>
>>>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>>>> when running nested, since those assisted flushes performed by L0
>>>>>> don't flush the L2 guests TLBs.
>>>>>>
>>>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>>>
>>>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>>>
>>>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>>>
>>>> And this would then flush _only_ guest TLBs?
>>>
>>> No, I think from Julien's proposal (if I understood it correctly)
>>> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
>>> previous to this patch (flush Xen's TLBs + HVM ASIDs).
>>
>> It looks like there might be confusion on what "guest TLBs" means. In my view this means any TLBs associated directly or indirectly with the guest. On Arm, this would be nuke:
>>     - guest virtual address -> guest physical address TLB entry
>>     - guest physical address -> host physical address TLB entry
>>     - guest virtual address -> host physical address TLB entry
>>
>> I would assume you want something similar on x86, right?
> 
> I don't think we'd want the middle of the three items you list,
> but I also don't see how this would be relevant here - flushing
> that is a p2m operation, not one affecting in-guest translations.

Apologies if this seems obvious to you, but why would you want to only 
flush in-guest translations in common code? What are you trying to 
protect against?

At least on Arm, you don't know whether the TLBs contains split or 
combined stage-2 (P2M) - stage-1 (guest PT) entries. So you have to nuke 
everything.

But this is already done as part of the P2M flush. I believe this should 
be the same on x86.

Cheers,
Roger Pau Monné March 20, 2020, 2:22 p.m. UTC | #18
On Fri, Mar 20, 2020 at 02:16:47PM +0100, Jan Beulich wrote:
> On 20.03.2020 10:01, Roger Pau Monné wrote:
> > On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
> >> On 19.03.2020 20:07, Julien Grall wrote:
> >>> On 19/03/2020 18:43, Roger Pau Monné wrote:
> >>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
> >>>>>
> >>>>>
> >>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
> >>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
> >>>>>>   >> Why can't you keep flush_tlb_mask() here?
> >>>>>>
> >>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
> >>>>>> changes to the phymap require an ASID flush on AMD hardware.
> >>>>>
> >>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
> >>>>> updated so it flush the ASID on AMD hardware.
> >>>>
> >>>> Current behavior previous to this patch is to flush the ASIDs on
> >>>> every TLB flush.
> >>>>
> >>>> flush_tlb_mask is too widely used on x86 in places where there's no
> >>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
> >>>> when running nested, since those assisted flushes performed by L0
> >>>> don't flush the L2 guests TLBs.
> >>>>
> >>>> I could keep current behavior and leave flush_tlb_mask also flushing the
> >>>> ASIDs, but that seems wrong as the function doesn't have anything in
> >>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
> >>>
> >>> I agree the name is confusing, I had to look at the implementation to understand what it does.
> >>>
> >>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
> >>
> >> And this would then flush _only_ guest TLBs?
> > 
> > No, I think from Julien's proposal (if I understood it correctly)
> > flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
> > previous to this patch (flush Xen's TLBs + HVM ASIDs).
> > 
> >>>> I would rather prefer the default to be to not flush the
> >>>> ASIDs, so that users need to specify so by passing the flag to
> >>>> flusk_mask.
> >>> That's x86 choice. For common, I would rather no introduce those flags until we have another arch that make use of it.
> >>
> >> The flags should perhaps indeed remain x86-specific, but suitable
> >> wrappers usable from common code should exist (as you suggest
> >> below).
> > 
> > I don't have a strong opinion re naming, are you OK with the names
> > proposed above?
> 
> Well, no - imo a function named e.g. flush_tlb_all_guests_cpumask() is
> not supposed to flush any host TLBs. But I'll also reply to Julien's
> subsequent reply in a minute.

It seems like the implementation of flush_tlb_mask on ARM and x86
already has different meanings, as the ARM one only flushes guests
TLBs but not Xen's one.

Alternatively I could code this as:

static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
{
    cpumask_t mask;

    cpumask_copy(&mask, &cpu_online_map);
    tlbflush_filter(&mask, tlbflush_timestamp);
    if ( !cpumask_empty(&mask) )
    {
        perfc_incr(need_flush_tlb_flush);
#if CONFIG_X86
        /*
         * filtered_flush_tlb_mask is used after modifying the p2m in
         * populate_physmap, Xen needs to trigger an ASID tickle as this is a
         * requirement on AMD hardware.
         */
        flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
#else
        flush_tlb_mask(&mask);
#endif
    }
}

And we can see later about getting rid of the filtered_flush_tlb_mask
calls in populate_physmap and alloc_heap_pages if they are really
unneeded, which will allows us to get rid of the function altogether.

Thanks, Roger.
Julien Grall March 20, 2020, 2:27 p.m. UTC | #19
On 20/03/2020 14:22, Roger Pau Monné wrote:
> static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
> {
>      cpumask_t mask;
> 
>      cpumask_copy(&mask, &cpu_online_map);
>      tlbflush_filter(&mask, tlbflush_timestamp);
>      if ( !cpumask_empty(&mask) )
>      {
>          perfc_incr(need_flush_tlb_flush);
> #if CONFIG_X86
>          /*
>           * filtered_flush_tlb_mask is used after modifying the p2m in
>           * populate_physmap, Xen needs to trigger an ASID tickle as this is a
>           * requirement on AMD hardware.
>           */

I don't think this comment is correct. populate_physmap() is only going 
to add entry in the P2M and therefore flush should not be needed.

The only reason the flush would happen in populate_physmap() is because 
we allocated a page that was required to be flush (see free.need_tbflush).

Cheers,
Julien Grall March 20, 2020, 2:43 p.m. UTC | #20
Hi,

On 20/03/2020 14:27, Julien Grall wrote:
> 
> 
> On 20/03/2020 14:22, Roger Pau Monné wrote:
>> static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
>> {
>>      cpumask_t mask;
>>
>>      cpumask_copy(&mask, &cpu_online_map);
>>      tlbflush_filter(&mask, tlbflush_timestamp);
>>      if ( !cpumask_empty(&mask) )
>>      {
>>          perfc_incr(need_flush_tlb_flush);
>> #if CONFIG_X86
>>          /*
>>           * filtered_flush_tlb_mask is used after modifying the p2m in
>>           * populate_physmap, Xen needs to trigger an ASID tickle as 
>> this is a
>>           * requirement on AMD hardware.
>>           */
> 
> I don't think this comment is correct. populate_physmap() is only going 
> to add entry in the P2M and therefore flush should not be needed.

I should have probably said "in most of the cases..." and ...

> 
> The only reason the flush would happen in populate_physmap() is because 
> we allocated a page that was required to be flush (see free.need_tbflush).

... extend this comment a bit more. The flush will happen when the page 
used to have an owner. So if there is no owner, there is no flush.

Therefore we can't rely on it if we really wanted to trigger an ASID 
tickle after a P2M update.

Cheers,
Roger Pau Monné March 20, 2020, 2:49 p.m. UTC | #21
On Fri, Mar 20, 2020 at 02:27:36PM +0000, Julien Grall wrote:
> 
> 
> On 20/03/2020 14:22, Roger Pau Monné wrote:
> > static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
> > {
> >      cpumask_t mask;
> > 
> >      cpumask_copy(&mask, &cpu_online_map);
> >      tlbflush_filter(&mask, tlbflush_timestamp);
> >      if ( !cpumask_empty(&mask) )
> >      {
> >          perfc_incr(need_flush_tlb_flush);
> > #if CONFIG_X86
> >          /*
> >           * filtered_flush_tlb_mask is used after modifying the p2m in
> >           * populate_physmap, Xen needs to trigger an ASID tickle as this is a
> >           * requirement on AMD hardware.
> >           */
> 
> I don't think this comment is correct. populate_physmap() is only going to
> add entry in the P2M and therefore flush should not be needed.

Since this is strictly only adding entries I think you are right and
the ASID tickle could be avoided, as long as we can assert the gfn was
empty (or didn't have the valid bit set) previous to being populated.

Or that the nested page tables code already handles all this and
perform the necessary flushes.

> The only reason the flush would happen in populate_physmap() is because we
> allocated a page that was required to be flush (see free.need_tbflush).

I think this is related to PV guests rather than HVM ones? For HVM we
would always flush whatever is needed after removing an entry from the
page tables.

Thanks, Roger.
Roger Pau Monné March 20, 2020, 2:52 p.m. UTC | #22
On Fri, Mar 20, 2020 at 02:43:38PM +0000, Julien Grall wrote:
> Hi,
> 
> On 20/03/2020 14:27, Julien Grall wrote:
> > 
> > 
> > On 20/03/2020 14:22, Roger Pau Monné wrote:
> > > static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
> > > {
> > >      cpumask_t mask;
> > > 
> > >      cpumask_copy(&mask, &cpu_online_map);
> > >      tlbflush_filter(&mask, tlbflush_timestamp);
> > >      if ( !cpumask_empty(&mask) )
> > >      {
> > >          perfc_incr(need_flush_tlb_flush);
> > > #if CONFIG_X86
> > >          /*
> > >           * filtered_flush_tlb_mask is used after modifying the p2m in
> > >           * populate_physmap, Xen needs to trigger an ASID tickle as
> > > this is a
> > >           * requirement on AMD hardware.
> > >           */
> > 
> > I don't think this comment is correct. populate_physmap() is only going
> > to add entry in the P2M and therefore flush should not be needed.
> 
> I should have probably said "in most of the cases..." and ...
> 
> > 
> > The only reason the flush would happen in populate_physmap() is because
> > we allocated a page that was required to be flush (see
> > free.need_tbflush).
> 
> ... extend this comment a bit more. The flush will happen when the page used
> to have an owner. So if there is no owner, there is no flush.
> 
> Therefore we can't rely on it if we really wanted to trigger an ASID tickle
> after a P2M update.

Right, so I can leave filtered_flush_tlb_mask as-is. Will prepare a
new patch.

Thanks, Roger.
Jan Beulich March 20, 2020, 2:56 p.m. UTC | #23
On 20.03.2020 15:17, Julien Grall wrote:
> Hi,
> 
> On 20/03/2020 13:19, Jan Beulich wrote:
>> On 20.03.2020 10:12, Julien Grall wrote:
>>> On 20/03/2020 09:01, Roger Pau Monné wrote:
>>>> On Fri, Mar 20, 2020 at 08:21:19AM +0100, Jan Beulich wrote:
>>>>> On 19.03.2020 20:07, Julien Grall wrote:
>>>>>> On 19/03/2020 18:43, Roger Pau Monné wrote:
>>>>>>> On Thu, Mar 19, 2020 at 06:07:44PM +0000, Julien Grall wrote:
>>>>>>>> On 19/03/2020 17:38, Roger Pau Monné wrote:
>>>>>>>>> On Thu, Mar 19, 2020 at 04:21:23PM +0000, Julien Grall wrote:
>>>>>>>>>     >> Why can't you keep flush_tlb_mask() here?
>>>>>>>>>
>>>>>>>>> Because filtered_flush_tlb_mask is used in populate_physmap, and
>>>>>>>>> changes to the phymap require an ASID flush on AMD hardware.
>>>>>>>>
>>>>>>>> I am afraid this does not yet explain me why flush_tlb_mask() could not be
>>>>>>>> updated so it flush the ASID on AMD hardware.
>>>>>>>
>>>>>>> Current behavior previous to this patch is to flush the ASIDs on
>>>>>>> every TLB flush.
>>>>>>>
>>>>>>> flush_tlb_mask is too widely used on x86 in places where there's no
>>>>>>> need to flush the ASIDs. This prevents using assisted flushes (by L0)
>>>>>>> when running nested, since those assisted flushes performed by L0
>>>>>>> don't flush the L2 guests TLBs.
>>>>>>>
>>>>>>> I could keep current behavior and leave flush_tlb_mask also flushing the
>>>>>>> ASIDs, but that seems wrong as the function doesn't have anything in
>>>>>>> it's name that suggests it also flushes the in-guest TLBs for HVM.
>>>>>>
>>>>>> I agree the name is confusing, I had to look at the implementation to understand what it does.
>>>>>>
>>>>>> How about renaming (or introducing) the function to flush_tlb_all_guests_mask() or flush_tlb_all_guests_cpumask()) ?
>>>>>
>>>>> And this would then flush _only_ guest TLBs?
>>>>
>>>> No, I think from Julien's proposal (if I understood it correctly)
>>>> flush_tlb_all_guests_mask would do what flush_tlb_mask currently does
>>>> previous to this patch (flush Xen's TLBs + HVM ASIDs).
>>>
>>> It looks like there might be confusion on what "guest TLBs" means. In my view this means any TLBs associated directly or indirectly with the guest. On Arm, this would be nuke:
>>>     - guest virtual address -> guest physical address TLB entry
>>>     - guest physical address -> host physical address TLB entry
>>>     - guest virtual address -> host physical address TLB entry
>>>
>>> I would assume you want something similar on x86, right?
>>
>> I don't think we'd want the middle of the three items you list,
>> but I also don't see how this would be relevant here - flushing
>> that is a p2m operation, not one affecting in-guest translations.
> 
> Apologies if this seems obvious to you, but why would you want to only flush in-guest translations in common code? What are you trying to protect against?

I've not looked at the particular use in common code, my comment
was only about what's still in context above.

> At least on Arm, you don't know whether the TLBs contains split or combined stage-2 (P2M) - stage-1 (guest PT) entries. So you have to nuke everything.

Flushing guest mappings (or giving the appearance to do so, by
switching ASID/PCID) is supposed to also flush combined
mappings of course. It is not supposed to flush p2m mappings,
because that's a different address space. It may well be that
in the place the function gets used flushing of everything is
needed, but then - as I think Roger has already said - the
p2m part of the flushing simply happens elsewhere on x86. (It
may well be that it could do with avoiding there and getting
done centrally from the common code invocation.)

> But this is already done as part of the P2M flush. I believe this should be the same on x86.

A p2m flush would deal with p2m and combined mappings; it
still wouldn't flush guest linear -> guest phys ones.

Jan
Jan Beulich March 20, 2020, 2:59 p.m. UTC | #24
On 20.03.2020 15:49, Roger Pau Monné wrote:
> On Fri, Mar 20, 2020 at 02:27:36PM +0000, Julien Grall wrote:
>>
>>
>> On 20/03/2020 14:22, Roger Pau Monné wrote:
>>> static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
>>> {
>>>      cpumask_t mask;
>>>
>>>      cpumask_copy(&mask, &cpu_online_map);
>>>      tlbflush_filter(&mask, tlbflush_timestamp);
>>>      if ( !cpumask_empty(&mask) )
>>>      {
>>>          perfc_incr(need_flush_tlb_flush);
>>> #if CONFIG_X86
>>>          /*
>>>           * filtered_flush_tlb_mask is used after modifying the p2m in
>>>           * populate_physmap, Xen needs to trigger an ASID tickle as this is a
>>>           * requirement on AMD hardware.
>>>           */
>>
>> I don't think this comment is correct. populate_physmap() is only going to
>> add entry in the P2M and therefore flush should not be needed.
> 
> Since this is strictly only adding entries I think you are right and
> the ASID tickle could be avoided, as long as we can assert the gfn was
> empty (or didn't have the valid bit set) previous to being populated.

While this may be true for x86, it's not guaranteed in general
that non-present translations may not also be put into TLBs.
So from common code there shouldn't be assumptions like this.

Jan
Roger Pau Monné March 20, 2020, 3:05 p.m. UTC | #25
On Fri, Mar 20, 2020 at 03:59:35PM +0100, Jan Beulich wrote:
> On 20.03.2020 15:49, Roger Pau Monné wrote:
> > On Fri, Mar 20, 2020 at 02:27:36PM +0000, Julien Grall wrote:
> >>
> >>
> >> On 20/03/2020 14:22, Roger Pau Monné wrote:
> >>> static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
> >>> {
> >>>      cpumask_t mask;
> >>>
> >>>      cpumask_copy(&mask, &cpu_online_map);
> >>>      tlbflush_filter(&mask, tlbflush_timestamp);
> >>>      if ( !cpumask_empty(&mask) )
> >>>      {
> >>>          perfc_incr(need_flush_tlb_flush);
> >>> #if CONFIG_X86
> >>>          /*
> >>>           * filtered_flush_tlb_mask is used after modifying the p2m in
> >>>           * populate_physmap, Xen needs to trigger an ASID tickle as this is a
> >>>           * requirement on AMD hardware.
> >>>           */
> >>
> >> I don't think this comment is correct. populate_physmap() is only going to
> >> add entry in the P2M and therefore flush should not be needed.
> > 
> > Since this is strictly only adding entries I think you are right and
> > the ASID tickle could be avoided, as long as we can assert the gfn was
> > empty (or didn't have the valid bit set) previous to being populated.
> 
> While this may be true for x86, it's not guaranteed in general
> that non-present translations may not also be put into TLBs.
> So from common code there shouldn't be assumptions like this.

But as pointed out by Julien filtered_flush_tlb_mask is exclusively
used in combination with accumulate_tlbflush, which only cares about
the need_tlbflush in the page struct, and hence if pages added to the
physmap didn't had an owner you won't end up calling
filtered_flush_tlb_mask at all.

So the ASID tickle must be performed somewhere else, because gating
the ASID flush on whether the page had a previous owner is not
correct.

Thanks, Roger.
diff mbox series

Patch

diff --git a/xen/arch/x86/flushtlb.c b/xen/arch/x86/flushtlb.c
index 03f92c23dc..c81e53c0ae 100644
--- a/xen/arch/x86/flushtlb.c
+++ b/xen/arch/x86/flushtlb.c
@@ -59,8 +59,6 @@  static u32 pre_flush(void)
         raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ);
 
  skip_clocktick:
-    hvm_flush_guest_tlbs();
-
     return t2;
 }
 
@@ -118,6 +116,7 @@  void switch_cr3_cr4(unsigned long cr3, unsigned long cr4)
     local_irq_save(flags);
 
     t = pre_flush();
+    hvm_flush_guest_tlbs();
 
     old_cr4 = read_cr4();
     ASSERT(!(old_cr4 & X86_CR4_PCIDE) || !(old_cr4 & X86_CR4_PGE));
@@ -221,6 +220,9 @@  unsigned int flush_area_local(const void *va, unsigned int flags)
             do_tlb_flush();
     }
 
+    if ( flags & FLUSH_HVM_ASID_CORE )
+        hvm_flush_guest_tlbs();
+
     if ( flags & FLUSH_CACHE )
     {
         const struct cpuinfo_x86 *c = &current_cpu_data;
diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c
index a6d5e39b02..004a89b4b9 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -118,7 +118,7 @@  int hap_track_dirty_vram(struct domain *d,
             p2m_change_type_range(d, begin_pfn, begin_pfn + nr,
                                   p2m_ram_rw, p2m_ram_logdirty);
 
-            flush_tlb_mask(d->dirty_cpumask);
+            flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
             memset(dirty_bitmap, 0xff, size); /* consider all pages dirty */
         }
@@ -205,7 +205,7 @@  static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
          * to be read-only, or via hardware-assisted log-dirty.
          */
         p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     }
     return 0;
 }
@@ -234,7 +234,7 @@  static void hap_clean_dirty_bitmap(struct domain *d)
      * be read-only, or via hardware-assisted log-dirty.
      */
     p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
-    flush_tlb_mask(d->dirty_cpumask);
+    flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 }
 
 /************************************************/
@@ -798,7 +798,7 @@  hap_write_p2m_entry(struct p2m_domain *p2m, unsigned long gfn, l1_pgentry_t *p,
 
     safe_write_pte(p, new);
     if ( old_flags & _PAGE_PRESENT )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     paging_unlock(d);
 
diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c
index abe5958a52..9c0750be17 100644
--- a/xen/arch/x86/mm/hap/nested_hap.c
+++ b/xen/arch/x86/mm/hap/nested_hap.c
@@ -84,7 +84,7 @@  nestedp2m_write_p2m_entry(struct p2m_domain *p2m, unsigned long gfn,
     safe_write_pte(p, new);
 
     if (old_flags & _PAGE_PRESENT)
-        flush_tlb_mask(p2m->dirty_cpumask);
+        flush_mask(p2m->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     paging_unlock(d);
 
diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c
index eb66077496..fbcea181ba 100644
--- a/xen/arch/x86/mm/p2m-pt.c
+++ b/xen/arch/x86/mm/p2m-pt.c
@@ -896,7 +896,8 @@  static void p2m_pt_change_entry_type_global(struct p2m_domain *p2m,
     unmap_domain_page(tab);
 
     if ( changed )
-         flush_tlb_mask(p2m->domain->dirty_cpumask);
+         flush_mask(p2m->domain->dirty_cpumask,
+                    FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 }
 
 static int p2m_pt_change_entry_type_range(struct p2m_domain *p2m,
diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c
index 469bb76429..f9d930b7a9 100644
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -613,7 +613,7 @@  void paging_log_dirty_range(struct domain *d,
 
     p2m_unlock(p2m);
 
-    flush_tlb_mask(d->dirty_cpumask);
+    flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 }
 
 /*
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index 121ddf1255..aa750eafae 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -363,7 +363,7 @@  static int oos_remove_write_access(struct vcpu *v, mfn_t gmfn,
     }
 
     if ( ftlb )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     return 0;
 }
@@ -939,7 +939,7 @@  static void _shadow_prealloc(struct domain *d, unsigned int pages)
                 /* See if that freed up enough space */
                 if ( d->arch.paging.shadow.free_pages >= pages )
                 {
-                    flush_tlb_mask(d->dirty_cpumask);
+                    flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
                     return;
                 }
             }
@@ -993,7 +993,7 @@  static void shadow_blow_tables(struct domain *d)
                                pagetable_get_mfn(v->arch.shadow_table[i]), 0);
 
     /* Make sure everyone sees the unshadowings */
-    flush_tlb_mask(d->dirty_cpumask);
+    flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 }
 
 void shadow_blow_tables_per_domain(struct domain *d)
@@ -1102,7 +1102,7 @@  mfn_t shadow_alloc(struct domain *d,
         if ( unlikely(!cpumask_empty(&mask)) )
         {
             perfc_incr(shadow_alloc_tlbflush);
-            flush_tlb_mask(&mask);
+            flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
         }
         /* Now safe to clear the page for reuse */
         clear_domain_page(page_to_mfn(sp));
@@ -2290,7 +2290,7 @@  void sh_remove_shadows(struct domain *d, mfn_t gmfn, int fast, int all)
 
     /* Need to flush TLBs now, so that linear maps are safe next time we
      * take a fault. */
-    flush_tlb_mask(d->dirty_cpumask);
+    flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     paging_unlock(d);
 }
@@ -3005,7 +3005,7 @@  static void sh_unshadow_for_p2m_change(struct domain *d, unsigned long gfn,
         {
             sh_remove_all_shadows_and_parents(d, mfn);
             if ( sh_remove_all_mappings(d, mfn, _gfn(gfn)) )
-                flush_tlb_mask(d->dirty_cpumask);
+                flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
         }
     }
 
@@ -3045,7 +3045,7 @@  static void sh_unshadow_for_p2m_change(struct domain *d, unsigned long gfn,
                 }
                 omfn = mfn_add(omfn, 1);
             }
-            flush_tlb_mask(&flushmask);
+            flush_mask(&flushmask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
             if ( npte )
                 unmap_domain_page(npte);
@@ -3332,7 +3332,7 @@  int shadow_track_dirty_vram(struct domain *d,
         }
     }
     if ( flush_tlb )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     goto out;
 
 out_sl1ma:
@@ -3402,7 +3402,7 @@  bool shadow_flush_tlb(bool (*flush_vcpu)(void *ctxt, struct vcpu *v),
     }
 
     /* Flush TLBs on all CPUs with dirty vcpu state. */
-    flush_tlb_mask(mask);
+    flush_mask(mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     /* Done. */
     for_each_vcpu ( d, v )
diff --git a/xen/arch/x86/mm/shadow/hvm.c b/xen/arch/x86/mm/shadow/hvm.c
index 1e6024c71f..509162cdce 100644
--- a/xen/arch/x86/mm/shadow/hvm.c
+++ b/xen/arch/x86/mm/shadow/hvm.c
@@ -591,7 +591,7 @@  static void validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
 
     if ( rc & SHADOW_SET_FLUSH )
         /* Need to flush TLBs to pick up shadow PT changes */
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     if ( rc & SHADOW_SET_ERROR )
     {
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index b6afc0fba4..667fca96c7 100644
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -3066,7 +3066,7 @@  static int sh_page_fault(struct vcpu *v,
         perfc_incr(shadow_rm_write_flush_tlb);
         smp_wmb();
         atomic_inc(&d->arch.paging.shadow.gtable_dirty_version);
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     }
 
 #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
@@ -3575,7 +3575,7 @@  static bool sh_invlpg(struct vcpu *v, unsigned long linear)
     if ( mfn_to_page(sl1mfn)->u.sh.type
          == SH_type_fl1_shadow )
     {
-        flush_tlb_local();
+        flush_local(FLUSH_TLB | FLUSH_HVM_ASID_CORE);
         return false;
     }
 
@@ -3810,7 +3810,7 @@  sh_update_linear_entries(struct vcpu *v)
          * table entry. But, without this change, it would fetch the wrong
          * value due to a stale TLB.
          */
-        flush_tlb_local();
+        flush_local(FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     }
 }
 
@@ -4011,7 +4011,7 @@  sh_update_cr3(struct vcpu *v, int do_locking, bool noflush)
      * (old) shadow linear maps in the writeable mapping heuristics. */
 #if GUEST_PAGING_LEVELS == 2
     if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow);
 #elif GUEST_PAGING_LEVELS == 3
     /* PAE guests have four shadow_table entries, based on the
@@ -4035,7 +4035,7 @@  sh_update_cr3(struct vcpu *v, int do_locking, bool noflush)
             }
         }
         if ( flush )
-            flush_tlb_mask(d->dirty_cpumask);
+            flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
         /* Now install the new shadows. */
         for ( i = 0; i < 4; i++ )
         {
@@ -4056,7 +4056,7 @@  sh_update_cr3(struct vcpu *v, int do_locking, bool noflush)
     }
 #elif GUEST_PAGING_LEVELS == 4
     if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow);
     if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) )
     {
@@ -4502,7 +4502,7 @@  static void sh_pagetable_dying(paddr_t gpa)
         }
     }
     if ( flush )
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
 
     /* Remember that we've seen the guest use this interface, so we
      * can rely on it using it in future, instead of guessing at
@@ -4539,7 +4539,7 @@  static void sh_pagetable_dying(paddr_t gpa)
         mfn_to_page(gmfn)->pagetable_dying = true;
         shadow_unhook_mappings(d, smfn, 1/* user pages only */);
         /* Now flush the TLB: we removed toplevel mappings. */
-        flush_tlb_mask(d->dirty_cpumask);
+        flush_mask(d->dirty_cpumask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     }
 
     /* Remember that we've seen the guest use this interface, so we
diff --git a/xen/include/asm-x86/flushtlb.h b/xen/include/asm-x86/flushtlb.h
index 2cfe4e6e97..579dc56803 100644
--- a/xen/include/asm-x86/flushtlb.h
+++ b/xen/include/asm-x86/flushtlb.h
@@ -105,6 +105,12 @@  void switch_cr3_cr4(unsigned long cr3, unsigned long cr4);
 #define FLUSH_VCPU_STATE 0x1000
  /* Flush the per-cpu root page table */
 #define FLUSH_ROOT_PGTBL 0x2000
+#if CONFIG_HVM
+ /* Flush all HVM guests linear TLB (using ASID/VPID) */
+#define FLUSH_HVM_ASID_CORE 0x4000
+#else
+#define FLUSH_HVM_ASID_CORE 0
+#endif
 
 /* Flush local TLBs/caches. */
 unsigned int flush_area_local(const void *va, unsigned int flags);
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index d0d095d9c7..02aad43042 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -644,7 +644,7 @@  static inline void filtered_flush_tlb_mask(uint32_t tlbflush_timestamp)
     if ( !cpumask_empty(&mask) )
     {
         perfc_incr(need_flush_tlb_flush);
-        flush_tlb_mask(&mask);
+        flush_mask(&mask, FLUSH_TLB | FLUSH_HVM_ASID_CORE);
     }
 }