diff options
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Timer.cpp | 51 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Timer.h | 27 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/init.cpp | 13 | ||||
-rw-r--r-- | Kernel/Prekernel/CMakeLists.txt | 1 |
4 files changed, 91 insertions, 1 deletions
diff --git a/Kernel/Prekernel/Arch/aarch64/Timer.cpp b/Kernel/Prekernel/Arch/aarch64/Timer.cpp new file mode 100644 index 0000000000..4d1f8812ca --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/Timer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Nico Weber <thakis@chromium.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/Prekernel/Arch/aarch64/MMIO.h> +#include <Kernel/Prekernel/Arch/aarch64/Timer.h> + +namespace Prekernel { + +// "12.1 System Timer Registers" / "10.2 System Timer Registers" +struct TimerRegisters { + u32 control_and_status; + u32 counter_low; + u32 counter_high; + u32 compare[4]; +}; + +// Bits of the `control_and_status` register. +// See "CS register" in Broadcom doc for details. +enum FlagBits { + SystemTimerMatch0 = 1 << 0, + SystemTimerMatch1 = 1 << 1, + SystemTimerMatch2 = 1 << 2, + SystemTimerMatch3 = 1 << 3, +}; + +Timer::Timer() + : m_registers(MMIO::the().peripheral<TimerRegisters>(0x3000)) +{ +} + +Timer& Timer::the() +{ + static Timer instance; + return instance; +} + +u64 Timer::microseconds_since_boot() +{ + u32 high = m_registers->counter_high; + u32 low = m_registers->counter_low; + if (high != m_registers->counter_high) { + high = m_registers->counter_high; + low = m_registers->counter_low; + } + return (static_cast<u64>(high) << 32) | low; +} + +} diff --git a/Kernel/Prekernel/Arch/aarch64/Timer.h b/Kernel/Prekernel/Arch/aarch64/Timer.h new file mode 100644 index 0000000000..278df3d493 --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/Timer.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Nico Weber <thakis@chromium.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Types.h> + +namespace Prekernel { + +struct TimerRegisters; + +class Timer { +public: + static Timer& the(); + + u64 microseconds_since_boot(); + +private: + Timer(); + + TimerRegisters volatile* m_registers; +}; + +} diff --git a/Kernel/Prekernel/Arch/aarch64/init.cpp b/Kernel/Prekernel/Arch/aarch64/init.cpp index f0833bf64e..85662770c5 100644 --- a/Kernel/Prekernel/Arch/aarch64/init.cpp +++ b/Kernel/Prekernel/Arch/aarch64/init.cpp @@ -6,6 +6,7 @@ #include <AK/Types.h> #include <Kernel/Prekernel/Arch/aarch64/Mailbox.h> +#include <Kernel/Prekernel/Arch/aarch64/Timer.h> #include <Kernel/Prekernel/Arch/aarch64/UART.h> extern "C" [[noreturn]] void halt(); @@ -24,7 +25,17 @@ extern "C" [[noreturn]] void init() uart.print_num(firmware_version); uart.print_str("\r\n"); - halt(); + auto& timer = Prekernel::Timer::the(); + u64 start_musec = 0; + for (;;) { + u64 now_musec; + while ((now_musec = timer.microseconds_since_boot()) - start_musec < 1'000'000) + ; + start_musec = now_musec; + uart.print_str("Timer: "); + uart.print_num(now_musec); + uart.print_str("\r\n"); + } } // FIXME: Share this with the Intel Prekernel. diff --git a/Kernel/Prekernel/CMakeLists.txt b/Kernel/Prekernel/CMakeLists.txt index 66167e6a14..d4f015aaa9 100644 --- a/Kernel/Prekernel/CMakeLists.txt +++ b/Kernel/Prekernel/CMakeLists.txt @@ -9,6 +9,7 @@ if ("${SERENITY_ARCH}" STREQUAL "aarch64") Arch/aarch64/Mailbox.cpp Arch/aarch64/MainIdRegister.cpp Arch/aarch64/MMIO.cpp + Arch/aarch64/Timer.cpp Arch/aarch64/UART.cpp Arch/aarch64/boot.S Arch/aarch64/init.cpp |