|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 5/7] x86: detect PIT aliasing on ports other than 0x4[0-3]
On Thu, May 11, 2023 at 02:07:12PM +0200, Jan Beulich wrote:
> ... in order to also deny Dom0 access through the alias ports. Without
> this it is only giving the impression of denying access to PIT. Unlike
> for CMOS/RTC, do detection pretty early, to avoid disturbing normal
> operation later on (even if typically we won't use much of the PIT).
>
> Like for CMOS/RTC a fundamental assumption of the probing is that reads
> from the probed alias port won't have side effects (beyond such that PIT
> reads have anyway) in case it does not alias the PIT's.
>
> At to the port 0x61 accesses: Unlike other accesses we do, this masks
> off the top four bits (in addition to the bottom two ones), following
> Intel chipset documentation saying that these (read-only) bits should
> only be written with zero.
As said in previous patches, I think this is likely too much risk for
little benefit. I understand the desire to uniformly deny access to
any ports that allow interaction with devices in use by Xen (or not
allowed to be used by dom0), but there's certainly a risk in
configuring such devices in the way that we do by finding a register
that can be read and written to.
I think if anything this alias detection should have a command line
option in order to disable it.
Do you also have figures if the greatly increased amount of accesses
add a noticeable boot time regression?
We are usually cautious is not performing more accesses than strictly
required.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> If Xen was running on top of another instance of itself (in HVM mode,
> not PVH, i.e. not as a shim), I'm afraid our vPIT logic would not allow
> the "Try to further make sure ..." check to pass in the Xen running on
> top: We don't respect the gate bit being clear when handling counter
> reads. (There are more unhandled [and unmentioned as being so] aspects
> of PIT behavior though, yet it's unclear in how far addressing at least
> some of them would be useful.)
>
> --- a/xen/arch/x86/dom0_build.c
> +++ b/xen/arch/x86/dom0_build.c
> @@ -504,7 +504,11 @@ int __init dom0_setup_permissions(struct
> }
>
> /* Interval Timer (PIT). */
> - rc |= ioports_deny_access(d, 0x40, 0x43);
> + for ( offs = 0, i = pit_alias_mask & -pit_alias_mask ?: 4;
> + offs <= pit_alias_mask; offs += i )
> + if ( !(offs & ~pit_alias_mask) )
> + rc |= ioports_deny_access(d, 0x40 + offs, 0x43 + offs);
> +
> /* PIT Channel 2 / PC Speaker Control. */
> rc |= ioports_deny_access(d, 0x61, 0x61);
>
> --- a/xen/arch/x86/include/asm/setup.h
> +++ b/xen/arch/x86/include/asm/setup.h
> @@ -53,6 +53,7 @@ extern unsigned long highmem_start;
> #endif
>
> extern unsigned int pic_alias_mask;
> +extern unsigned int pit_alias_mask;
>
> extern int8_t opt_smt;
>
> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -425,6 +425,69 @@ static struct platform_timesource __init
> .resume = resume_pit,
> };
>
> +unsigned int __initdata pit_alias_mask;
> +
> +static void __init probe_pit_alias(void)
> +{
> + unsigned int mask = 0x1c;
> + uint8_t val = 0;
> +
> + /*
> + * Use channel 2 in mode 0 for probing. In this mode even a non-initial
> + * count is loaded independent of counting being / becoming enabled.
> Thus
> + * we have a 16-bit value fully under our control, to write and then
> check
> + * whether we can also read it back unaltered.
> + */
> +
> + /* Turn off speaker output and disable channel 2 counting. */
> + outb(inb(0x61) & 0x0c, 0x61);
> +
> + outb((2 << 6) | (3 << 4) | (0 << 1), PIT_MODE); /* Mode 0, LSB/MSB. */
> +
> + do {
> + uint8_t val2;
> + unsigned int offs;
> +
> + outb(val, PIT_CH2);
> + outb(val ^ 0xff, PIT_CH2);
> +
> + /* Wait for the Null Count bit to clear. */
> + do {
> + /* Latch status. */
> + outb((3 << 6) | (1 << 5) | (1 << 3), PIT_MODE);
> +
> + /* Try to make sure we're actually having a PIT here. */
> + val2 = inb(PIT_CH2);
> + if ( (val2 & ~(3 << 6)) != ((3 << 4) | (0 << 1)) )
> + return;
> + } while ( val2 & (1 << 6) );
We should have some kind of timeout here, just in case...
> +
> + /*
> + * Try to further make sure we're actually having a PIT here.
> + *
> + * NB: Deliberately |, not ||, as we always want both reads.
> + */
> + val2 = inb(PIT_CH2);
> + if ( (val2 ^ val) | (inb(PIT_CH2) ^ val ^ 0xff) )
> + return;
> +
> + for ( offs = mask & -mask; offs <= mask; offs <<= 1 )
> + {
> + if ( !(mask & offs) )
> + continue;
> + val2 = inb(PIT_CH2 + offs);
> + if ( (val2 ^ val) | (inb(PIT_CH2 + offs) ^ val ^ 0xff) )
> + mask &= ~offs;
> + }
> + } while ( mask && (val += 0x0b) ); /* Arbitrary uneven number. */
> +
> + if ( mask )
> + {
> + dprintk(XENLOG_INFO, "PIT aliasing mask: %02x\n", mask);
> + pit_alias_mask = mask;
> + }
Is it fine to leave counting disabled for channel 2?
Shouldn't we restore the previous gate value?
Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |