arch/arm64/qemu: Use the PL031 RTC of the virt machine.

The QEMU virt machine has a PL031 RTC at 0x09010000 (SPI 2), which QEMU
sets from the host clock.  qemu-armv8a did not register it, so the
system time started at CONFIG_START_YEAR, and files on a host share
(v9fs, hostfs) had times years in the future.

With CONFIG_RTC_PL031, up_rtc_initialize() now registers the PL031 as
the RTC, so the system time starts at the host's time.

The new option QEMU_RTC_PL031_SYNC makes the boot wait (up to a second)
for the RTC second to change.  The PL031 counts whole seconds, so
without the wait the time starts up to a second behind the host.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-10-08 21:57:36 +02:00 • committed by Alan C. Assis
parent baa21f197d
commit 7c6307bebf
4 changed files with 101 additions and 0 deletions

View file

@ -30,4 +30,7 @@ endif()
if(CONFIG_PM)
list(APPEND SRCS qemu_initialize.c)
endif()
if(CONFIG_RTC_PL031)
list(APPEND SRCS qemu_rtc.c)
endif()
target_sources(arch PRIVATE ${SRCS})

View file

@ -47,4 +47,29 @@ config ARCH_CHIP_QEMU_WITH_HV
endmenu # "Qemu Chip Selection"
config QEMU_RTC_PL031_BASE
hex "PL031 RTC base address"
default 0x09010000
depends on RTC_PL031
---help---
Physical address of the PL031 RTC of the QEMU virt machine.
config QEMU_RTC_PL031_IRQ
int "PL031 RTC interrupt"
default 34
depends on RTC_PL031
---help---
Interrupt of the PL031 RTC of the QEMU virt machine (SPI 2).
config QEMU_RTC_PL031_SYNC
bool "Start the system time at an RTC second boundary"
default n
depends on RTC_PL031
---help---
The PL031 counts whole seconds, so the system time starts up to a
second behind the host. Files that the host writes then look
up to a second in the future, and make warns about clock skew.
With this option the boot waits (up to a second) for the RTC
second to change, so the time is correct to a few milliseconds.
endif # ARCH_CHIP_QEMU

View file

@ -36,3 +36,7 @@ endif
ifeq ($(CONFIG_PM),y)
CHIP_CSRCS += qemu_initialize.c
endif
ifeq ($(CONFIG_RTC_PL031),y)
CHIP_CSRCS += qemu_rtc.c
endif

View file

@ -0,0 +1,69 @@
/****************************************************************************
* arch/arm64/src/qemu/qemu_rtc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/timers/pl031.h>
#include <nuttx/timers/rtc.h>
#include <nuttx/timers/arch_rtc.h>
#include "arm64_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_rtc_initialize
*
* Description:
* Register the PL031 RTC of the QEMU virt machine. QEMU sets it from the
* host clock (-rtc base=utc by default), so the system time starts at the
* host's time.
*
****************************************************************************/
int up_rtc_initialize(void)
{
FAR struct rtc_lowerhalf_s *lower;
#ifdef CONFIG_QEMU_RTC_PL031_SYNC
/* The PL031 counts whole seconds, so the system time would start up to a
* second late. Wait until the second changes: the time read next is
* then correct to a few milliseconds. Register 0 is the data register.
*/
uint32_t second = getreg32(CONFIG_QEMU_RTC_PL031_BASE);
while (getreg32(CONFIG_QEMU_RTC_PL031_BASE) == second);
#endif
lower = pl031_initialize(CONFIG_QEMU_RTC_PL031_BASE,
CONFIG_QEMU_RTC_PL031_IRQ);
up_rtc_set_lowerhalf(lower, true);
return rtc_initialize(0, lower);
}