This patch provides basic implementation of a subset of functionality of the PrimeCell Real Time Clock (PL031) device that is enough to capture boot time as number of seconds since epoch. Please note that this implementation does not handle any host clock drift and provides current time functionality that is only accurate up to a second.
This patch effectively fixes 2 unit tests - tst-time.cc and tst-timerfd.cc. Fixes #1091 Signed-off-by: Waldemar Kozaczuk <[email protected]> --- Makefile | 1 + arch/aarch64/arch-dtb.cc | 19 +++++++++++++ arch/aarch64/arch-dtb.hh | 7 +++++ arch/aarch64/arm-clock.cc | 18 +++++++++++-- drivers/pl031.cc | 56 +++++++++++++++++++++++++++++++++++++++ drivers/pl031.hh | 50 ++++++++++++++++++++++++++++++++++ scripts/test.py | 4 +-- 7 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 drivers/pl031.cc create mode 100644 drivers/pl031.hh diff --git a/Makefile b/Makefile index 833803cf..f33b1cdb 100644 --- a/Makefile +++ b/Makefile @@ -835,6 +835,7 @@ endif # x64 ifeq ($(arch),aarch64) drivers += drivers/mmio-isa-serial.o drivers += drivers/pl011.o +drivers += drivers/pl031.o drivers += drivers/cadence-uart.o drivers += drivers/xenconsole.o drivers += drivers/virtio.o diff --git a/arch/aarch64/arch-dtb.cc b/arch/aarch64/arch-dtb.cc index 24ac9267..63db8b00 100644 --- a/arch/aarch64/arch-dtb.cc +++ b/arch/aarch64/arch-dtb.cc @@ -190,6 +190,25 @@ u64 dtb_get_uart(int *irqid) return retval; } +u64 dtb_get_rtc() +{ + u64 retval; + int node; size_t len; + + if (!dtb) + return 0; + + node = fdt_node_offset_by_compatible(dtb, -1, "arm,pl031"); + if (node < 0) + return 0; + + len = dtb_get_reg(node, &retval); + if (!len) + return 0; + + return retval; +} + u64 dtb_get_mmio_serial_console(int *irqid) { int node; diff --git a/arch/aarch64/arch-dtb.hh b/arch/aarch64/arch-dtb.hh index 0aebb4b3..10e1c859 100644 --- a/arch/aarch64/arch-dtb.hh +++ b/arch/aarch64/arch-dtb.hh @@ -49,6 +49,13 @@ size_t dtb_get_phys_memory(u64 *addr); */ u64 dtb_get_uart(int *irqid); +/* u64 dtb_get_rtc() + * + * return the base address of the RTC (PL031) + * device or returns zero on failure. + */ +u64 dtb_get_rtc(); + /* u64 dtb_get_mmio_serial_console(int *irqid) * * return the base address of the serial console and writes the diff --git a/arch/aarch64/arm-clock.cc b/arch/aarch64/arm-clock.cc index c1f4b277..7d11e454 100644 --- a/arch/aarch64/arm-clock.cc +++ b/arch/aarch64/arm-clock.cc @@ -7,6 +7,7 @@ #include "drivers/clockevent.hh" #include "drivers/clock.hh" +#include "drivers/pl031.hh" #include "arm-clock.hh" #include <osv/interrupt.hh> #include "exceptions.hh" @@ -36,6 +37,8 @@ protected: u32 freq_hz; /* frequency in Hz (updates per second) */ friend class arm_clock_events; +private: + u64 _boot_time; }; arm_clock::arm_clock() { @@ -49,6 +52,13 @@ arm_clock::arm_clock() { #if CONF_logger_debug debug_early_u64("arm_clock(): frequency read as ", freq_hz); #endif + u64 rtc_address = dtb_get_rtc(); + if (rtc_address) { + pl031 rtc(rtc_address); + _boot_time = rtc.wallclock_ns(); + } else { + _boot_time = 0; + } } static __attribute__((constructor(init_prio::clock))) void setup_arm_clock() @@ -70,12 +80,16 @@ s64 arm_clock::uptime() s64 arm_clock::time() { - return uptime(); + //Given that _boot_time came from RTC which gives only 1 second + //precision the result time() is only accurate up to a second + //On top of this, this implementation does not account for any host + //clock drifts + return _boot_time + uptime(); } s64 arm_clock::boot_time() { - return uptime(); + return _boot_time; } u64 arm_clock::processor_to_nano(u64 ticks) diff --git a/drivers/pl031.cc b/drivers/pl031.cc new file mode 100644 index 00000000..b81b38b9 --- /dev/null +++ b/drivers/pl031.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 Waldemar Kozaczuk + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ + +#include "pl031.hh" +#include <osv/mmu.hh> + +/* spec: see PrimeCell Real Time Clock (PL031) Technical Reference Manual. + * implemented according to Revision: r1p3. + * See https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf + * Please note that this a minimal implementation of a subset of the + * functionality which is enough to read the current time in seconds + * at the boot time. + */ + +#define rtc_reg(ADDR,REG_OFFSET) (*(volatile u32 *)(ADDR+REG_OFFSET)) + +pl031::pl031(u64 address) +{ + _address = address; + mmu::linear_map((void *)_address, _address, mmu::page_size, mmu::page_size, + mmu::mattr::dev); +} + +pl031::~pl031() +{ + mmu::munmap((void*)_address, mmu::page_size); +} + +uint64_t pl031::wallclock_ns() +{ + // Let us read various identificatin registers to + // verify that it is indeed a valid PL031 device + if( rtc_reg(_address, RTCPeriphID0) == RTCPeriphID0_val && + rtc_reg(_address, RTCPeriphID1) == RTCPeriphID1_val && + (rtc_reg(_address, RTCPeriphID2) & RTCPeriphID2_mask) == RTCPeriphID2_val && + rtc_reg(_address, RTCPeriphID3) == RTCPeriphID3_val && + rtc_reg(_address, RTCPCellID0) == RTCPCellID0_val && + rtc_reg(_address, RTCPCellID1) == RTCPCellID1_val && + rtc_reg(_address, RTCPCellID2) == RTCPCellID2_val && + rtc_reg(_address, RTCPCellID3) == RTCPCellID3_val) { + // Read value of RTC which is number of seconds since epoch + // representing current time + u64 epoch_time_in_seconds = rtc_reg(_address, RTCDR); +#if CONF_logger_debug + debug_early_u64("pl031::wallclock_ns(): RTC seconds since epoch read as ", epoch_time_in_seconds); +#endif + return epoch_time_in_seconds * 1000000000; + } else { + debug_early("pl031: could no detect!"); + return 0; + } +} diff --git a/drivers/pl031.hh b/drivers/pl031.hh new file mode 100644 index 00000000..7b594ff4 --- /dev/null +++ b/drivers/pl031.hh @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Waldemar Kozaczuk + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ + +#ifndef OSV_PL031_HH +#define OSV_PL031_HH + +#include <osv/types.h> + +#define RTCDR 0x000 /* data */ +#define RTCMR 0x004 /* match */ +#define RTCLR 0x008 /* load */ +#define RTCCR 0x00c /* control */ +#define RTCIMSC 0x010 /* interrupt mask set or clear */ +#define RTCRIS 0x014 /* raw interrupt status */ +#define RTCMIS 0x018 /* masked interrupt status */ +#define RTCICR 0x01c /* interrupt clear */ +#define RTCPeriphID0 0xfe0 /* peripheral ID bits [7:0] */ +#define RTCPeriphID1 0xfe4 /* peripheral ID bits [15:8] */ +#define RTCPeriphID2 0xfe8 /* peripheral ID bits [23:16] */ +#define RTCPeriphID3 0xfec /* peripheral ID bits [31:24] */ +#define RTCPCellID0 0xff0 /* PrimeCell ID bits [7:0] */ +#define RTCPCellID1 0xff4 /* PrimeCell ID bits [7:0] */ +#define RTCPCellID2 0xff8 /* PrimeCell ID bits [7:0] */ +#define RTCPCellID3 0xffc /* PrimeCell ID bits [7:0] */ + +#define RTCPeriphID0_val 0x31 +#define RTCPeriphID1_val 0x10 +#define RTCPeriphID2_mask 0x0f +#define RTCPeriphID2_val 0x04 +#define RTCPeriphID3_val 0x00 + +#define RTCPCellID0_val 0x0d +#define RTCPCellID1_val 0xf0 +#define RTCPCellID2_val 0x05 +#define RTCPCellID3_val 0xb1 + +class pl031 { +public: + pl031(u64 address); + ~pl031(); + uint64_t wallclock_ns(); +private: + u64 _address; +}; + +#endif //OSV_PL031_HH diff --git a/scripts/test.py b/scripts/test.py index 8e3882af..f0c12d6c 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -31,7 +31,7 @@ firecracker_disabled_list= [ "tcp_close_without_reading_on_qemu" ] -#At this point there are 120 out of 131 unit tests that pass on aarch64. +#At this point there are 122 out of 131 unit tests that pass on aarch64. #The remaining ones are disabled below until we fix various #issues that prevent those tests from passing. aarch64_disabled_list= [ @@ -46,8 +46,6 @@ aarch64_disabled_list= [ #Please see comments on the right side for more details "tst-elf-permissions.so", # Infinite page fault "tst-mmap.so", # Infinite page fault - "tst-time.so", # One assertion fails - 'tst-time.cc(70): fatal error: in "time_time": critical check (static_cast<time_t>(0)) != (t1) has failed' - "tst-timerfd.so", # Some assertions fail - 'SUMMARY: 212 tests, 10 failures' #These tests fail due to some other shortcomings in the test scripts "tracing_smoke_test", "tcp_close_without_reading_on_fc", -- 2.30.2 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20210319153359.69109-1-jwkozaczuk%40gmail.com.
