[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 2/2] x86/time: prefer CMOS over EFI_GET_TIME
On 30/08/2024 10:52 am, Roger Pau Monne wrote: > The EFI_GET_TIME implementation is well known to be broken for many firmware > implementations, for Xen the result on such implementations are: > > ----[ Xen-4.19-unstable x86_64 debug=y Tainted: C ]---- > CPU: 0 > RIP: e008:[<0000000062ccfa70>] 0000000062ccfa70 > [...] > Xen call trace: > [<0000000062ccfa70>] R 0000000062ccfa70 > [<00000000732e9a3f>] S 00000000732e9a3f > [<ffff82d04034f34f>] F arch/x86/time.c#get_cmos_time+0x1b3/0x26e > [<ffff82d04045926f>] F init_xen_time+0x28/0xa4 > [<ffff82d040454bc4>] F __start_xen+0x1ee7/0x2578 > [<ffff82d040203334>] F __high_start+0x94/0xa0 > > Pagetable walk from 0000000062ccfa70: > L4[0x000] = 000000207ef1c063 ffffffffffffffff > L3[0x001] = 000000005d6c0063 ffffffffffffffff > L2[0x116] = 8000000062c001e3 ffffffffffffffff (PSE) > > **************************************** > Panic on CPU 0: > FATAL PAGE FAULT > [error_code=0011] > Faulting linear address: 0000000062ccfa70 > **************************************** > > Swap the preference to default to CMOS first, and EFI later, in an attempt to > use EFI_GET_TIME as a last resort option only. Note that Linux for example > doesn't allow calling the get_time method, and instead provides a dummy > handler > that unconditionally returns EFI_UNSUPPORTED on x86-64. > > Such change in the preferences requires some re-arranging of the function > logic, so that panic messages with workaround suggestions are suitably > printed. > > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> > --- > xen/arch/x86/time.c | 26 +++++++++++++++++++------- > 1 file changed, 19 insertions(+), 7 deletions(-) > > diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c > index 272ca2468ea6..0eee954809a9 100644 > --- a/xen/arch/x86/time.c > +++ b/xen/arch/x86/time.c > @@ -1305,24 +1305,36 @@ static unsigned long get_cmos_time(void) > static bool __read_mostly cmos_rtc_probe; > boolean_param("cmos-rtc-probe", cmos_rtc_probe); > > + if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) ) > + cmos_rtc_probe = false; > + > + if ( (!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) || > + cmos_rtc_probe) && read_cmos_time(&rtc, cmos_rtc_probe) ) > + return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, > rtc.sec); > + > if ( efi_enabled(EFI_RS) ) > { > unsigned long res = efi_get_time(); > > if ( res ) > return res; > + > + panic("Broken EFI_GET_TIME %s\n", > + !cmos_rtc_probe ? "try booting with \"cmos-rtc-probe\" option" > + : "and no CMOS RTC found"); > } > > - if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) ) > - cmos_rtc_probe = false; > - else if ( system_state < SYS_STATE_smp_boot && !cmos_rtc_probe ) > + /* > + * No viable clock source found. Attempt to provide some guidance to the > + * user about possible workarounds to boot Xen on the system. > + */ > + ASSERT(system_state < SYS_STATE_smp_boot); > + > + if ( !cmos_rtc_probe ) > panic("System with no CMOS RTC advertised must be booted from EFI" > " (or with command line option \"cmos-rtc-probe\")\n"); > > - if ( unlikely(!read_cmos_time(&rtc, cmos_rtc_probe)) ) > - panic("No CMOS RTC found - system must be booted from EFI\n"); > - > - return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec); > + panic("No CMOS RTC found - system must be booted from EFI\n"); > } > > static unsigned int __ro_after_init cmos_alias_mask; Hmm, I know I said "fix the crash first, cleanup later" on the prior patch, but I'm tempted to retract that. This is very hard to follow. Going back to first principles, at runtime we need USE_{XEN,RTC,EFI} to select between the various methods available. At boot, we need to figure out what to do. I think we want an init_wallclock_time() split out of get_cmos_time() (which is badly named anyway, given EFI), and called from init_xen_time() only. In particular, the init stuff should not be re-evaluated in time_{suspend,resume}(). Various details we have to work with: * ACPI_FADT_NO_CMOS_RTC, although we know this is falsely set on some platforms, hence the whole probing logic. * Booted on an EFI system, although we know EFI_GET_TIME is broken on millions of systems, and we only find this out with a #PF in the middle of EFI-RS. Furthermore, more-major-OSes-than-us strictly veto the use of this service, and it's not only Linux; it's Windows too. Personally, I think "cmos-rtc-probe" is inappropriate/insufficient. It ought to be wc-time=guess|xen|rtc|efi. We should be able to influence the behaviour more than a boolean "probe or not". The Xen case might be better as "hypervisor", although I can't see any evidence of Viridian having a virtualised wallclock interface. I think the init logic wants to be: * If ACPI says we have an RTC, use it. * If ACPI says we have no RTC, probe to see if it's really there. * If we genuinely seem to not have an RTC, probe EFI. This would be quite invasive in the #PF handler, but not impossible. That said, I'm still holding out hope that we can simply delete Xen's need for wallclock time. Xen only uses wallclock time for the non-default console_timestamps=date, but even then it's uncorrelate with dom0 changing the platform time, leading to actively-misleading log files. There's a reason why "time since boot" is the norm. ~Andrew
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |