• Thomas Gleixner's avatar
    rtc: mc146818: Prevent reading garbage · 05a0302c
    Thomas Gleixner authored
    
    
    The MC146818 driver is prone to read garbage from the RTC. There are
    several issues all related to the update cycle of the MC146818. The chip
    increments seconds obviously once per second and indicates that by a bit in
    a register. The bit goes high 244us before the actual update starts. During
    the update the readout of the time values is undefined.
    
    The code just checks whether the update in progress bit (UIP) is set before
    reading the clock. If it's set it waits arbitrary 20ms before retrying,
    which is ample because the maximum update time is ~2ms.
    
    But this check does not guarantee that the UIP bit goes high and the actual
    update happens during the readout. So the following can happen
    
     0.997 	       UIP = False
       -> Interrupt/NMI/preemption
     0.998	       UIP -> True
     0.999	       Readout	<- Undefined
    
    To prevent this rework the code so it checks UIP before and after the
    readout and if set after the readout try again.
    
    But that's not enough to cover the following:
    
     0.997 	       UIP = False
     	       Readout seconds
       -> NMI (or vCPU scheduled out)
     0.998	       UIP -> True
     	       update completes
    	       UIP -> False
     1.000	       Readout	minutes,....
     	       UIP check succeeds
    
    That can make the readout wrong up to 59 seconds.
    
    To prevent this, read the seconds value before the first UIP check,
    validate it after checking UIP and after reading out the rest.
    
    It's amazing that the original i386 code had this actually correct and
    the generic implementation of the MC146818 driver got it wrong in 2002 and
    it stayed that way until today.
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Acked-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
    Link: https://lore.kernel.org/r/20201206220541.594826678@linutronix.de
    05a0302c
rtc-mc146818-lib.c 5.27 KB