diff mbox series

[for-4.14] x86/rtc: provide mediated access to RTC for PVH dom0

Message ID 20200605075006.51238-1-roger.pau@citrix.com (mailing list archive)
State Superseded
Headers show
Series [for-4.14] x86/rtc: provide mediated access to RTC for PVH dom0 | expand

Commit Message

Roger Pau Monné June 5, 2020, 7:50 a.m. UTC
At some point (maybe PVHv1?) mediated access to the RTC was provided
for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
point this code has been made PV specific and unhooked from the
current PVH IO path. This patch provides such mediated access to the
RTC for PVH dom0, just like it's provided for a classic PV dom0.

Instead of re-using the PV paths implement such handler together with
the vRTC code for HVM, so that calling rtc_init will setup the
appropriate handlers for all HVM based guests.

Without this a Linux PVH dom0 will read garbage when trying to access
the RTC, and one vCPU will be constantly looping in
rtc_timer_do_work.

Note that such issue doesn't happen on domUs because the ACPI
NO_CMOS_RTC flag is set in FADT, which prevents the OS from accessing
the RTC.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
for-4.14 reasoning: the fix is completely isolated to PVH dom0, and as
such the risk is very low of causing issues to other guests types, but
without this fix one vCPU when using a Linux dom0 will be constantly
looping over rtc_timer_do_work with 100% CPU usage, at least when
using Linux 4.19 or newer.
---
 xen/arch/x86/hvm/rtc.c | 69 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

Comments

Paul Durrant June 5, 2020, 8:03 a.m. UTC | #1
> -----Original Message-----
> From: Roger Pau Monne <roger.pau@citrix.com>
> Sent: 05 June 2020 08:50
> To: xen-devel@lists.xenproject.org
> Cc: paul@xen.org; Roger Pau Monne <roger.pau@citrix.com>; Jan Beulich <jbeulich@suse.com>; Andrew
> Cooper <andrew.cooper3@citrix.com>; Wei Liu <wl@xen.org>
> Subject: [PATCH for-4.14] x86/rtc: provide mediated access to RTC for PVH dom0
> 
> At some point (maybe PVHv1?) mediated access to the RTC was provided
> for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
> point this code has been made PV specific and unhooked from the
> current PVH IO path. This patch provides such mediated access to the
> RTC for PVH dom0, just like it's provided for a classic PV dom0.
> 
> Instead of re-using the PV paths implement such handler together with
> the vRTC code for HVM, so that calling rtc_init will setup the
> appropriate handlers for all HVM based guests.
> 
> Without this a Linux PVH dom0 will read garbage when trying to access
> the RTC, and one vCPU will be constantly looping in
> rtc_timer_do_work.
> 
> Note that such issue doesn't happen on domUs because the ACPI
> NO_CMOS_RTC flag is set in FADT, which prevents the OS from accessing
> the RTC.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> ---
> for-4.14 reasoning: the fix is completely isolated to PVH dom0, and as
> such the risk is very low of causing issues to other guests types, but
> without this fix one vCPU when using a Linux dom0 will be constantly
> looping over rtc_timer_do_work with 100% CPU usage, at least when
> using Linux 4.19 or newer.
> ---

I can't say I'm a big fan of the code duplication with emul-priv-op.c, but it's not much code and it does keep this patch small. If the maintainers are happy to ack then consider this...

Release-acked-by: Paul Durrant <paul@xen.org>

>  xen/arch/x86/hvm/rtc.c | 69 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c
> index 5bbbdc0e0f..5d637cf018 100644
> --- a/xen/arch/x86/hvm/rtc.c
> +++ b/xen/arch/x86/hvm/rtc.c
> @@ -808,10 +808,79 @@ void rtc_reset(struct domain *d)
>      s->pt.source = PTSRC_isa;
>  }
> 
> +/* RTC mediator for HVM hardware domain. */
> +static unsigned int hw_read(unsigned int port)
> +{
> +    const struct domain *currd = current->domain;
> +    unsigned long flags;
> +    unsigned int data = 0;
> +
> +    switch ( port )
> +    {
> +    case RTC_PORT(0):
> +          data = currd->arch.cmos_idx;
> +          break;
> +
> +    case RTC_PORT(1):
> +          spin_lock_irqsave(&rtc_lock, flags);
> +          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
> +          data = inb(RTC_PORT(1));
> +          spin_unlock_irqrestore(&rtc_lock, flags);
> +          break;
> +    }
> +
> +    return data;
> +}
> +
> +static void hw_write(unsigned int port, unsigned int data)
> +{
> +    struct domain *currd = current->domain;
> +    unsigned long flags;
> +
> +    switch ( port )
> +    {
> +    case RTC_PORT(0):
> +          currd->arch.cmos_idx = data;
> +          break;
> +
> +    case RTC_PORT(1):
> +          spin_lock_irqsave(&rtc_lock, flags);
> +          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
> +          outb(data, RTC_PORT(1));
> +          spin_unlock_irqrestore(&rtc_lock, flags);
> +          break;
> +    }
> +}
> +
> +static int hw_rtc_io(int dir, unsigned int port, unsigned int size,
> +                     uint32_t *val)
> +{
> +    if ( size != 1 )
> +    {
> +        gdprintk(XENLOG_WARNING, "bad RTC access size (%u)\n", size);
> +        *val = ~0;
> +        return X86EMUL_OKAY;
> +    }
> +
> +    if ( dir == IOREQ_WRITE )
> +        hw_write(port, *val);
> +    else
> +        *val = hw_read(port);
> +
> +    return X86EMUL_OKAY;
> +}
> +
>  void rtc_init(struct domain *d)
>  {
>      RTCState *s = domain_vrtc(d);
> 
> +    if ( is_hardware_domain(d) )
> +    {
> +        /* Hardware domain gets mediated access to the physical RTC. */
> +        register_portio_handler(d, RTC_PORT(0), 2, hw_rtc_io);
> +        return;
> +    }
> +
>      if ( !has_vrtc(d) )
>          return;
> 
> --
> 2.26.2
Jan Beulich June 5, 2020, 8:48 a.m. UTC | #2
On 05.06.2020 09:50, Roger Pau Monne wrote:
> At some point (maybe PVHv1?) mediated access to the RTC was provided
> for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
> point this code has been made PV specific and unhooked from the
> current PVH IO path.

I don't suppose you've identified the commit which did? This would
help deciding whether / how far to backport such a change.

> This patch provides such mediated access to the
> RTC for PVH dom0, just like it's provided for a classic PV dom0.
> 
> Instead of re-using the PV paths implement such handler together with
> the vRTC code for HVM, so that calling rtc_init will setup the
> appropriate handlers for all HVM based guests.

Hooking this into rtc_init() makes sense as long as it's really
just the RTC. Looking at the PV code you're cloning from, I
wonder though whether pv_pit_handler() should also regain callers
for PVH. As it stands the function is called for PV only, yet was
deliberately put/kept outside of pv/.

So along the lines of Paul's reply I think it would be better if
code was shared between PV and PVH Dom0, perhaps by breaking out
respective pieces from guest_io_{read,write}().

> Note that such issue doesn't happen on domUs because the ACPI
> NO_CMOS_RTC flag is set in FADT, which prevents the OS from accessing
> the RTC.

Will it? I'm pretty sure Linux may (have?) ignore(d) this flag.

> --- a/xen/arch/x86/hvm/rtc.c
> +++ b/xen/arch/x86/hvm/rtc.c
> @@ -808,10 +808,79 @@ void rtc_reset(struct domain *d)
>      s->pt.source = PTSRC_isa;
>  }
>  
> +/* RTC mediator for HVM hardware domain. */
> +static unsigned int hw_read(unsigned int port)
> +{
> +    const struct domain *currd = current->domain;
> +    unsigned long flags;
> +    unsigned int data = 0;
> +
> +    switch ( port )
> +    {
> +    case RTC_PORT(0):
> +          data = currd->arch.cmos_idx;
> +          break;
> +
> +    case RTC_PORT(1):
> +          spin_lock_irqsave(&rtc_lock, flags);
> +          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
> +          data = inb(RTC_PORT(1));
> +          spin_unlock_irqrestore(&rtc_lock, flags);

Avoiding to clone the original code would also avoid omissions
like the ioports_access_permitted() calls you've dropped from
here as well as the write counterpart. This may seem redundant
as we never deny access right now, but should imo be there in
case we decide to do (e.g. on NO_CMOS_RTC systems).

Actually, "never" wasn't quite right I think: Late-hwdom
creation will revoke access from dom0 and instead grant it to
the new hwdom. Without the check, dom0 would continue to be
able to access the RTC.

Jan
Roger Pau Monné June 5, 2020, 8:54 a.m. UTC | #3
On Fri, Jun 05, 2020 at 09:03:11AM +0100, Paul Durrant wrote:
> > -----Original Message-----
> > From: Roger Pau Monne <roger.pau@citrix.com>
> > Sent: 05 June 2020 08:50
> > To: xen-devel@lists.xenproject.org
> > Cc: paul@xen.org; Roger Pau Monne <roger.pau@citrix.com>; Jan Beulich <jbeulich@suse.com>; Andrew
> > Cooper <andrew.cooper3@citrix.com>; Wei Liu <wl@xen.org>
> > Subject: [PATCH for-4.14] x86/rtc: provide mediated access to RTC for PVH dom0
> > 
> > At some point (maybe PVHv1?) mediated access to the RTC was provided
> > for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
> > point this code has been made PV specific and unhooked from the
> > current PVH IO path. This patch provides such mediated access to the
> > RTC for PVH dom0, just like it's provided for a classic PV dom0.
> > 
> > Instead of re-using the PV paths implement such handler together with
> > the vRTC code for HVM, so that calling rtc_init will setup the
> > appropriate handlers for all HVM based guests.
> > 
> > Without this a Linux PVH dom0 will read garbage when trying to access
> > the RTC, and one vCPU will be constantly looping in
> > rtc_timer_do_work.
> > 
> > Note that such issue doesn't happen on domUs because the ACPI
> > NO_CMOS_RTC flag is set in FADT, which prevents the OS from accessing
> > the RTC.
> > 
> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> > ---
> > for-4.14 reasoning: the fix is completely isolated to PVH dom0, and as
> > such the risk is very low of causing issues to other guests types, but
> > without this fix one vCPU when using a Linux dom0 will be constantly
> > looping over rtc_timer_do_work with 100% CPU usage, at least when
> > using Linux 4.19 or newer.
> > ---
> 
> I can't say I'm a big fan of the code duplication with emul-priv-op.c, but it's not much code and it does keep this patch small. If the maintainers are happy to ack then consider this...

Calling guest_io_{write/read} straight away is no acceptable IMO (and it
would have to be moved out of emul-priv-op.c), and splitting the RTC
accessors into separate helpers seemed like a lot of churn for the
actual code that such helpers would contain.

> Release-acked-by: Paul Durrant <paul@xen.org>

Thanks.
Roger Pau Monné June 5, 2020, 9:20 a.m. UTC | #4
On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
> On 05.06.2020 09:50, Roger Pau Monne wrote:
> > At some point (maybe PVHv1?) mediated access to the RTC was provided
> > for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
> > point this code has been made PV specific and unhooked from the
> > current PVH IO path.
> 
> I don't suppose you've identified the commit which did? This would
> help deciding whether / how far to backport such a change.

I've attempted to, but failed to find the exact commit. I guess it
might have happened at ecaba067e1e433 when guest_io_{read/write} was
moved into emul-priv-op.c and made PV specific, but that's just a hint.

> > This patch provides such mediated access to the
> > RTC for PVH dom0, just like it's provided for a classic PV dom0.
> > 
> > Instead of re-using the PV paths implement such handler together with
> > the vRTC code for HVM, so that calling rtc_init will setup the
> > appropriate handlers for all HVM based guests.
> 
> Hooking this into rtc_init() makes sense as long as it's really
> just the RTC. Looking at the PV code you're cloning from, I
> wonder though whether pv_pit_handler() should also regain callers
> for PVH. As it stands the function is called for PV only, yet was
> deliberately put/kept outside of pv/.

IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
enable it for PVHv2 because no one really knew why the PIT was
actually needed for by dom0.

I think it's in emul-i8524.c (outside of pv/) because it calls into
static functions on that file that are also used by HVM
(handle_pit_io)?

> So along the lines of Paul's reply I think it would be better if
> code was shared between PV and PVH Dom0, perhaps by breaking out
> respective pieces from guest_io_{read,write}().

OK, I can try but it will involve more code churn.

> 
> > Note that such issue doesn't happen on domUs because the ACPI
> > NO_CMOS_RTC flag is set in FADT, which prevents the OS from accessing
> > the RTC.
> 
> Will it? I'm pretty sure Linux may (have?) ignore(d) this flag.

Seems like it's acknowledged now:

https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/acpi/boot.c#L969

PVHv2 support is fairly recent anyway, and I wouldn't recommend using
anything below Linux 4.19, which also has this implemented.

> > --- a/xen/arch/x86/hvm/rtc.c
> > +++ b/xen/arch/x86/hvm/rtc.c
> > @@ -808,10 +808,79 @@ void rtc_reset(struct domain *d)
> >      s->pt.source = PTSRC_isa;
> >  }
> >  
> > +/* RTC mediator for HVM hardware domain. */
> > +static unsigned int hw_read(unsigned int port)
> > +{
> > +    const struct domain *currd = current->domain;
> > +    unsigned long flags;
> > +    unsigned int data = 0;
> > +
> > +    switch ( port )
> > +    {
> > +    case RTC_PORT(0):
> > +          data = currd->arch.cmos_idx;
> > +          break;
> > +
> > +    case RTC_PORT(1):
> > +          spin_lock_irqsave(&rtc_lock, flags);
> > +          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
> > +          data = inb(RTC_PORT(1));
> > +          spin_unlock_irqrestore(&rtc_lock, flags);
> 
> Avoiding to clone the original code would also avoid omissions
> like the ioports_access_permitted() calls you've dropped from
> here as well as the write counterpart. This may seem redundant
> as we never deny access right now, but should imo be there in
> case we decide to do (e.g. on NO_CMOS_RTC systems).
> 
> Actually, "never" wasn't quite right I think: Late-hwdom
> creation will revoke access from dom0 and instead grant it to
> the new hwdom. Without the check, dom0 would continue to be
> able to access the RTC.

TBH I'm not sure late-hwdom switching from an initial PVH domain will
work work very well, as we would already have to modify the vmcs/vmcb
io_bitmap in order to convey the changes to the allowed IO port ranges
which we don't do now.

Let me see if I can split the helpers.

Roger.
Jan Beulich June 5, 2020, 10:05 a.m. UTC | #5
On 05.06.2020 11:20, Roger Pau Monné wrote:
> On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
>> On 05.06.2020 09:50, Roger Pau Monne wrote:
>>> At some point (maybe PVHv1?) mediated access to the RTC was provided
>>> for PVH dom0 using the PV code paths (guest_io_{write/read}). At some
>>> point this code has been made PV specific and unhooked from the
>>> current PVH IO path.
>>
>> I don't suppose you've identified the commit which did? This would
>> help deciding whether / how far to backport such a change.
> 
> I've attempted to, but failed to find the exact commit. I guess it
> might have happened at ecaba067e1e433 when guest_io_{read/write} was
> moved into emul-priv-op.c and made PV specific, but that's just a hint.

Looks like it was never hooked up for PVHv2, and removed together
with a lot of other PVHv1 code by your 33e5c32559e1.

>>> This patch provides such mediated access to the
>>> RTC for PVH dom0, just like it's provided for a classic PV dom0.
>>>
>>> Instead of re-using the PV paths implement such handler together with
>>> the vRTC code for HVM, so that calling rtc_init will setup the
>>> appropriate handlers for all HVM based guests.
>>
>> Hooking this into rtc_init() makes sense as long as it's really
>> just the RTC. Looking at the PV code you're cloning from, I
>> wonder though whether pv_pit_handler() should also regain callers
>> for PVH. As it stands the function is called for PV only, yet was
>> deliberately put/kept outside of pv/.
> 
> IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
> enable it for PVHv2 because no one really knew why the PIT was
> actually needed for by dom0.

I think the reason PV Dom0 has it applies to PVH Dom0 as well:
At least back at the time there were video BIOSes needing this.
As it now turns out to have been a mistake to not enable the
RTC handling for v2, I would still think it would be better to
enable the PIT logic as well there, just to be on the safe side.

> I think it's in emul-i8524.c (outside of pv/) because it calls into
> static functions on that file that are also used by HVM
> (handle_pit_io)?

Ah, likely.

>>> --- a/xen/arch/x86/hvm/rtc.c
>>> +++ b/xen/arch/x86/hvm/rtc.c
>>> @@ -808,10 +808,79 @@ void rtc_reset(struct domain *d)
>>>      s->pt.source = PTSRC_isa;
>>>  }
>>>  
>>> +/* RTC mediator for HVM hardware domain. */
>>> +static unsigned int hw_read(unsigned int port)
>>> +{
>>> +    const struct domain *currd = current->domain;
>>> +    unsigned long flags;
>>> +    unsigned int data = 0;
>>> +
>>> +    switch ( port )
>>> +    {
>>> +    case RTC_PORT(0):
>>> +          data = currd->arch.cmos_idx;
>>> +          break;
>>> +
>>> +    case RTC_PORT(1):
>>> +          spin_lock_irqsave(&rtc_lock, flags);
>>> +          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
>>> +          data = inb(RTC_PORT(1));
>>> +          spin_unlock_irqrestore(&rtc_lock, flags);
>>
>> Avoiding to clone the original code would also avoid omissions
>> like the ioports_access_permitted() calls you've dropped from
>> here as well as the write counterpart. This may seem redundant
>> as we never deny access right now, but should imo be there in
>> case we decide to do (e.g. on NO_CMOS_RTC systems).
>>
>> Actually, "never" wasn't quite right I think: Late-hwdom
>> creation will revoke access from dom0 and instead grant it to
>> the new hwdom. Without the check, dom0 would continue to be
>> able to access the RTC.
> 
> TBH I'm not sure late-hwdom switching from an initial PVH domain will
> work work very well, as we would already have to modify the vmcs/vmcb
> io_bitmap in order to convey the changes to the allowed IO port ranges
> which we don't do now.

FAOD: I didn't mean to suggest I believe this transition would
be working right now. But if someone wanted to make it work,
they shouldn't be put at risk to unknowingly leave the original
dom0 with more permissions than it's supposed to have.

Jan
Roger Pau Monné June 5, 2020, 2:16 p.m. UTC | #6
On Fri, Jun 05, 2020 at 12:05:12PM +0200, Jan Beulich wrote:
> On 05.06.2020 11:20, Roger Pau Monné wrote:
> > On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
> >> On 05.06.2020 09:50, Roger Pau Monne wrote:
> >>> This patch provides such mediated access to the
> >>> RTC for PVH dom0, just like it's provided for a classic PV dom0.
> >>>
> >>> Instead of re-using the PV paths implement such handler together with
> >>> the vRTC code for HVM, so that calling rtc_init will setup the
> >>> appropriate handlers for all HVM based guests.
> >>
> >> Hooking this into rtc_init() makes sense as long as it's really
> >> just the RTC. Looking at the PV code you're cloning from, I
> >> wonder though whether pv_pit_handler() should also regain callers
> >> for PVH. As it stands the function is called for PV only, yet was
> >> deliberately put/kept outside of pv/.
> > 
> > IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
> > enable it for PVHv2 because no one really knew why the PIT was
> > actually needed for by dom0.
> 
> I think the reason PV Dom0 has it applies to PVH Dom0 as well:
> At least back at the time there were video BIOSes needing this.
> As it now turns out to have been a mistake to not enable the
> RTC handling for v2, I would still think it would be better to
> enable the PIT logic as well there, just to be on the safe side.

I have to admit I haven't used video output very much with PVH, I've
had reports of people having success with it, but I have no idea how
many failures there might be.

Enabling the PIT for PVH dom0 is mostly a matter of adding
XEN_X86_EMU_PIT to the emulation flags, like it's currently done for
PV dom0.

There's going to be a slight issue though, which is that the PIT will
try to inject the interrupts using the PIC IRQ0, and thus would either
need to also enable the PIC, or to instead set the timer source to
PTSRC_ioapic instead of PTSRC_isa and use GSI 0. I haven't actually
tried whether this would work, but seems better than enabling the PIC.

Roger.
Jan Beulich June 5, 2020, 2:20 p.m. UTC | #7
On 05.06.2020 16:16, Roger Pau Monné wrote:
> On Fri, Jun 05, 2020 at 12:05:12PM +0200, Jan Beulich wrote:
>> On 05.06.2020 11:20, Roger Pau Monné wrote:
>>> On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
>>>> On 05.06.2020 09:50, Roger Pau Monne wrote:
>>>>> This patch provides such mediated access to the
>>>>> RTC for PVH dom0, just like it's provided for a classic PV dom0.
>>>>>
>>>>> Instead of re-using the PV paths implement such handler together with
>>>>> the vRTC code for HVM, so that calling rtc_init will setup the
>>>>> appropriate handlers for all HVM based guests.
>>>>
>>>> Hooking this into rtc_init() makes sense as long as it's really
>>>> just the RTC. Looking at the PV code you're cloning from, I
>>>> wonder though whether pv_pit_handler() should also regain callers
>>>> for PVH. As it stands the function is called for PV only, yet was
>>>> deliberately put/kept outside of pv/.
>>>
>>> IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
>>> enable it for PVHv2 because no one really knew why the PIT was
>>> actually needed for by dom0.
>>
>> I think the reason PV Dom0 has it applies to PVH Dom0 as well:
>> At least back at the time there were video BIOSes needing this.
>> As it now turns out to have been a mistake to not enable the
>> RTC handling for v2, I would still think it would be better to
>> enable the PIT logic as well there, just to be on the safe side.
> 
> I have to admit I haven't used video output very much with PVH, I've
> had reports of people having success with it, but I have no idea how
> many failures there might be.
> 
> Enabling the PIT for PVH dom0 is mostly a matter of adding
> XEN_X86_EMU_PIT to the emulation flags, like it's currently done for
> PV dom0.
> 
> There's going to be a slight issue though, which is that the PIT will
> try to inject the interrupts using the PIC IRQ0, and thus would either
> need to also enable the PIC, or to instead set the timer source to
> PTSRC_ioapic instead of PTSRC_isa and use GSI 0. I haven't actually
> tried whether this would work, but seems better than enabling the PIC.

But what we do for PV Dom0 doesn't go as far as injecting IRQs (let
alone IRQ0). It's just the few port accesses that we allow them to
make (successfully, i.e. seeing the relevant bare hardware bits).

Jan
Roger Pau Monné June 5, 2020, 2:45 p.m. UTC | #8
On Fri, Jun 05, 2020 at 04:20:31PM +0200, Jan Beulich wrote:
> On 05.06.2020 16:16, Roger Pau Monné wrote:
> > On Fri, Jun 05, 2020 at 12:05:12PM +0200, Jan Beulich wrote:
> >> On 05.06.2020 11:20, Roger Pau Monné wrote:
> >>> On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
> >>>> On 05.06.2020 09:50, Roger Pau Monne wrote:
> >>>>> This patch provides such mediated access to the
> >>>>> RTC for PVH dom0, just like it's provided for a classic PV dom0.
> >>>>>
> >>>>> Instead of re-using the PV paths implement such handler together with
> >>>>> the vRTC code for HVM, so that calling rtc_init will setup the
> >>>>> appropriate handlers for all HVM based guests.
> >>>>
> >>>> Hooking this into rtc_init() makes sense as long as it's really
> >>>> just the RTC. Looking at the PV code you're cloning from, I
> >>>> wonder though whether pv_pit_handler() should also regain callers
> >>>> for PVH. As it stands the function is called for PV only, yet was
> >>>> deliberately put/kept outside of pv/.
> >>>
> >>> IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
> >>> enable it for PVHv2 because no one really knew why the PIT was
> >>> actually needed for by dom0.
> >>
> >> I think the reason PV Dom0 has it applies to PVH Dom0 as well:
> >> At least back at the time there were video BIOSes needing this.
> >> As it now turns out to have been a mistake to not enable the
> >> RTC handling for v2, I would still think it would be better to
> >> enable the PIT logic as well there, just to be on the safe side.
> > 
> > I have to admit I haven't used video output very much with PVH, I've
> > had reports of people having success with it, but I have no idea how
> > many failures there might be.
> > 
> > Enabling the PIT for PVH dom0 is mostly a matter of adding
> > XEN_X86_EMU_PIT to the emulation flags, like it's currently done for
> > PV dom0.
> > 
> > There's going to be a slight issue though, which is that the PIT will
> > try to inject the interrupts using the PIC IRQ0, and thus would either
> > need to also enable the PIC, or to instead set the timer source to
> > PTSRC_ioapic instead of PTSRC_isa and use GSI 0. I haven't actually
> > tried whether this would work, but seems better than enabling the PIC.
> 
> But what we do for PV Dom0 doesn't go as far as injecting IRQs (let
> alone IRQ0). It's just the few port accesses that we allow them to
> make (successfully, i.e. seeing the relevant bare hardware bits).

It seems cleaner to me to just provide the whole thing for PVH, rather
than what we do for classic PV, in which we allow some accesses to the
real hardware.

I understand there's no need to give dom0 access to the real PIC, and
that using the emulated one should work just fine.

Roger.
Roger Pau Monné June 5, 2020, 2:54 p.m. UTC | #9
On Fri, Jun 05, 2020 at 04:45:28PM +0200, Roger Pau Monné wrote:
> On Fri, Jun 05, 2020 at 04:20:31PM +0200, Jan Beulich wrote:
> > On 05.06.2020 16:16, Roger Pau Monné wrote:
> > > On Fri, Jun 05, 2020 at 12:05:12PM +0200, Jan Beulich wrote:
> > >> On 05.06.2020 11:20, Roger Pau Monné wrote:
> > >>> On Fri, Jun 05, 2020 at 10:48:48AM +0200, Jan Beulich wrote:
> > >>>> On 05.06.2020 09:50, Roger Pau Monne wrote:
> > >>>>> This patch provides such mediated access to the
> > >>>>> RTC for PVH dom0, just like it's provided for a classic PV dom0.
> > >>>>>
> > >>>>> Instead of re-using the PV paths implement such handler together with
> > >>>>> the vRTC code for HVM, so that calling rtc_init will setup the
> > >>>>> appropriate handlers for all HVM based guests.
> > >>>>
> > >>>> Hooking this into rtc_init() makes sense as long as it's really
> > >>>> just the RTC. Looking at the PV code you're cloning from, I
> > >>>> wonder though whether pv_pit_handler() should also regain callers
> > >>>> for PVH. As it stands the function is called for PV only, yet was
> > >>>> deliberately put/kept outside of pv/.
> > >>>
> > >>> IIRC pv_pit_handler was also used by PVHv1 dom0, but we decided to not
> > >>> enable it for PVHv2 because no one really knew why the PIT was
> > >>> actually needed for by dom0.
> > >>
> > >> I think the reason PV Dom0 has it applies to PVH Dom0 as well:
> > >> At least back at the time there were video BIOSes needing this.
> > >> As it now turns out to have been a mistake to not enable the
> > >> RTC handling for v2, I would still think it would be better to
> > >> enable the PIT logic as well there, just to be on the safe side.
> > > 
> > > I have to admit I haven't used video output very much with PVH, I've
> > > had reports of people having success with it, but I have no idea how
> > > many failures there might be.
> > > 
> > > Enabling the PIT for PVH dom0 is mostly a matter of adding
> > > XEN_X86_EMU_PIT to the emulation flags, like it's currently done for
> > > PV dom0.
> > > 
> > > There's going to be a slight issue though, which is that the PIT will
> > > try to inject the interrupts using the PIC IRQ0, and thus would either
> > > need to also enable the PIC, or to instead set the timer source to
> > > PTSRC_ioapic instead of PTSRC_isa and use GSI 0. I haven't actually
> > > tried whether this would work, but seems better than enabling the PIC.
> > 
> > But what we do for PV Dom0 doesn't go as far as injecting IRQs (let
> > alone IRQ0). It's just the few port accesses that we allow them to
> > make (successfully, i.e. seeing the relevant bare hardware bits).
> 
> It seems cleaner to me to just provide the whole thing for PVH, rather
> than what we do for classic PV, in which we allow some accesses to the
> real hardware.
> 
> I understand there's no need to give dom0 access to the real PIC, and
                                                               ^ PIT.
> that using the emulated one should work just fine.
> 
> Roger.
>
diff mbox series

Patch

diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c
index 5bbbdc0e0f..5d637cf018 100644
--- a/xen/arch/x86/hvm/rtc.c
+++ b/xen/arch/x86/hvm/rtc.c
@@ -808,10 +808,79 @@  void rtc_reset(struct domain *d)
     s->pt.source = PTSRC_isa;
 }
 
+/* RTC mediator for HVM hardware domain. */
+static unsigned int hw_read(unsigned int port)
+{
+    const struct domain *currd = current->domain;
+    unsigned long flags;
+    unsigned int data = 0;
+
+    switch ( port )
+    {
+    case RTC_PORT(0):
+          data = currd->arch.cmos_idx;
+          break;
+
+    case RTC_PORT(1):
+          spin_lock_irqsave(&rtc_lock, flags);
+          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
+          data = inb(RTC_PORT(1));
+          spin_unlock_irqrestore(&rtc_lock, flags);
+          break;
+    }
+
+    return data;
+}
+
+static void hw_write(unsigned int port, unsigned int data)
+{
+    struct domain *currd = current->domain;
+    unsigned long flags;
+
+    switch ( port )
+    {
+    case RTC_PORT(0):
+          currd->arch.cmos_idx = data;
+          break;
+
+    case RTC_PORT(1):
+          spin_lock_irqsave(&rtc_lock, flags);
+          outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
+          outb(data, RTC_PORT(1));
+          spin_unlock_irqrestore(&rtc_lock, flags);
+          break;
+    }
+}
+
+static int hw_rtc_io(int dir, unsigned int port, unsigned int size,
+                     uint32_t *val)
+{
+    if ( size != 1 )
+    {
+        gdprintk(XENLOG_WARNING, "bad RTC access size (%u)\n", size);
+        *val = ~0;
+        return X86EMUL_OKAY;
+    }
+
+    if ( dir == IOREQ_WRITE )
+        hw_write(port, *val);
+    else
+        *val = hw_read(port);
+
+    return X86EMUL_OKAY;
+}
+
 void rtc_init(struct domain *d)
 {
     RTCState *s = domain_vrtc(d);
 
+    if ( is_hardware_domain(d) )
+    {
+        /* Hardware domain gets mediated access to the physical RTC. */
+        register_portio_handler(d, RTC_PORT(0), 2, hw_rtc_io);
+        return;
+    }
+
     if ( !has_vrtc(d) )
         return;