[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, Oct 26, 2023 at 02:31:27PM +0200, Jan Beulich wrote: > On 26.10.2023 12:25, Roger Pau Monné wrote: > > 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. > > Well, we could have command line options (for each of the RTC/CMOS, > PIC, and PIT probing allowing the alias masks to be specified (so we > don't need to probe). A value of 1 would uniformly mean "no probing, > no aliases" (as all three decode the low bit, so aliasing can happen > there). We could further make the default of these variables (yes/no, > no actual mask values of course) controllable by a Kconfig setting. If you want to make this more fine grained, or even allow the user to provide custom masks that's all fine, but there's already dom0_ioports_disable that allows disabling a list of IO port ranges. What I would require is a way to avoid all the probing, so that we could return to the previous behavior. > >> --- 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... > > Hmm, I indeed did consider the need for a timeout here. With what > we've done up to here we already assume a functioning PIT, verifying > simply as we go. The issue with truly using some form of timeout is > the determination of how long to wait at most. I would likely make it based on iterations, could you get some figures on how many iterations it takes for the bit to be clear? I would think something like 1000 should be enough, but really have no idea. > >> + > >> + /* > >> + * 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? > > See init_pit(), which also doesn't restore anything. The system is under > our control, and we have no other use for channel 2. (I really had > restore logic here initially, but then dropped it for said reason.) It might be used by a PV dom0 (see hwdom_pit_access()), so I wonder whether we should try to hand off as Xen found it. Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |