From afdabe9df8b54119e8587d1f855f28eccc4e6c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Thu, 26 Sep 2013 17:03:33 +0200 Subject: [PATCH] hw: enable performance counter on ARMv6 and ARMv7 To actually enable the performance counter 'perf_counter' has to be added to the SPECS make variable. Fixes #893. --- base-hw/include/kernel/perf_counter.h | 31 +++ base-hw/lib/mk/arm_v6/enable_perf_counter.mk | 3 + base-hw/lib/mk/arm_v7/enable_perf_counter.mk | 3 + base-hw/lib/mk/perf_counter.mk | 3 + base-hw/lib/mk/perf_counter/perf_counter.mk | 1 + base-hw/src/core/arm_v6/perf_counter.cc | 125 ++++++++++++ base-hw/src/core/arm_v7/perf_counter.cc | 192 +++++++++++++++++++ base-hw/src/core/kernel.cc | 4 + base-hw/src/core/perf_counter.cc | 25 +++ base-hw/src/core/target.inc | 2 +- 10 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 base-hw/include/kernel/perf_counter.h create mode 100644 base-hw/lib/mk/arm_v6/enable_perf_counter.mk create mode 100644 base-hw/lib/mk/arm_v7/enable_perf_counter.mk create mode 100644 base-hw/lib/mk/perf_counter.mk create mode 100644 base-hw/lib/mk/perf_counter/perf_counter.mk create mode 100644 base-hw/src/core/arm_v6/perf_counter.cc create mode 100644 base-hw/src/core/arm_v7/perf_counter.cc create mode 100644 base-hw/src/core/perf_counter.cc diff --git a/base-hw/include/kernel/perf_counter.h b/base-hw/include/kernel/perf_counter.h new file mode 100644 index 0000000000..da9ffee47a --- /dev/null +++ b/base-hw/include/kernel/perf_counter.h @@ -0,0 +1,31 @@ +/* + * \brief Performance counter specific functions + * \author Josef Soentgen + * \date 2013-09-26 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _PERF_COUNTER_H_ +#define _PERF_COUNTER_H_ + +namespace Kernel { + + class Perf_counter + { + public: + + void enable(); + }; + + + extern Perf_counter *perf_counter(); + +} + +#endif /* _PERF_COUNTER_H_ */ diff --git a/base-hw/lib/mk/arm_v6/enable_perf_counter.mk b/base-hw/lib/mk/arm_v6/enable_perf_counter.mk new file mode 100644 index 0000000000..a4ceaa15dc --- /dev/null +++ b/base-hw/lib/mk/arm_v6/enable_perf_counter.mk @@ -0,0 +1,3 @@ +SRC_CC = perf_counter.cc + +vpath %.cc $(REP_DIR)/src/core/arm_v6 diff --git a/base-hw/lib/mk/arm_v7/enable_perf_counter.mk b/base-hw/lib/mk/arm_v7/enable_perf_counter.mk new file mode 100644 index 0000000000..57d2b6fd59 --- /dev/null +++ b/base-hw/lib/mk/arm_v7/enable_perf_counter.mk @@ -0,0 +1,3 @@ +SRC_CC = perf_counter.cc + +vpath %.cc $(REP_DIR)/src/core/arm_v7 diff --git a/base-hw/lib/mk/perf_counter.mk b/base-hw/lib/mk/perf_counter.mk new file mode 100644 index 0000000000..7ac7036573 --- /dev/null +++ b/base-hw/lib/mk/perf_counter.mk @@ -0,0 +1,3 @@ +SRC_CC = perf_counter.cc + +vpath %.cc $(REP_DIR)/src/core/ diff --git a/base-hw/lib/mk/perf_counter/perf_counter.mk b/base-hw/lib/mk/perf_counter/perf_counter.mk new file mode 100644 index 0000000000..f0118a5a53 --- /dev/null +++ b/base-hw/lib/mk/perf_counter/perf_counter.mk @@ -0,0 +1 @@ +LIBS += enable_perf_counter diff --git a/base-hw/src/core/arm_v6/perf_counter.cc b/base-hw/src/core/arm_v6/perf_counter.cc new file mode 100644 index 0000000000..436bc5fe77 --- /dev/null +++ b/base-hw/src/core/arm_v6/perf_counter.cc @@ -0,0 +1,125 @@ +/* + * \brief Performance counter for ARMv6 + * \author Josef Soentgen + * \date 2013-09-26 + * + * The naming is based on ARM1176JZF-S Technical Reference Manual. + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +/* base-hw includes */ +#include + +using namespace Genode; + +/** + * Performance Monitor Control Register + */ +struct Pmcr : Register<32> +{ + struct E : Bitfield<0,1> { }; /* enable all counter */ + struct P : Bitfield<1,1> { }; /* count register reset */ + struct C : Bitfield<2,1> { }; /* cycle counter reset */ + struct D : Bitfield<3,1> { }; /* cycle counter divider */ + + static access_t enable_and_reset() + { + return E::bits(1) | + P::bits(1) | + C::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c15, c12, 0" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %[v], c15, c12, 0" :: [v]"r"(v) : ); + } +}; + + +/** + * System Validation Counter Register + */ +struct Sysvalcntrr : Register<32> +{ + struct Resetcntr : Bitfield<0,1> { }; /* reset all counter */ + + static access_t reset_counter() + { + return Resetcntr::bits(0); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c15, c12, 1" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %[v], c15, c12, 1" :: [v]"r"(v) : ); + } +}; + + +/** + * Secure User and Non-secure Access Validation Control Register + */ +struct Accvalctlr : Register<32> +{ + struct V : Bitfield<0,1> { }; /* enable access in user-mode */ + + static access_t enable_user_access() + { + return V::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c15, c9, 0" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %[v], c15, c9, 0" :: [v]"r"(v) : ); + } +}; + + +void Kernel::Perf_counter::enable() +{ + /* enable counters and disable overflow interrupt. */ + Pmcr::access_t v = Pmcr::enable_and_reset() | + Pmcr::D::bits(1); /* count every 64 cycles */ + Pmcr::write(v); + + Sysvalcntrr::write(Sysvalcntrr::reset_counter()); + + /* enable user-mode access */ + Accvalctlr::write(Accvalctlr::enable_user_access()); +} + + +Kernel::Perf_counter* Kernel::perf_counter() +{ + static Kernel::Perf_counter inst; + return &inst; +} diff --git a/base-hw/src/core/arm_v7/perf_counter.cc b/base-hw/src/core/arm_v7/perf_counter.cc new file mode 100644 index 0000000000..26dffeb710 --- /dev/null +++ b/base-hw/src/core/arm_v7/perf_counter.cc @@ -0,0 +1,192 @@ +/* + * \brief Performance counter ARMv7 + * \author Josef Soentgen + * \date 2013-09-26 + * + * The naming is based on ARM Architecture Reference Manual ARMv7-A. + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +/* base-hw includes */ +#include + +using namespace Genode; + +/** + * Performance Monitor Control Register + */ +struct Pmcr : Register<32> +{ + struct E : Bitfield<0,1> { }; /* enable all counters */ + struct P : Bitfield<1,1> { }; /* performance counter reset */ + struct C : Bitfield<2,1> { }; /* cycle counter reset */ + struct D : Bitfield<3,1> { }; /* clock divider */ + + static access_t enable_and_reset() + { + return E::bits(1) | + P::bits(1) | + C::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c9, c12, 0" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %[v], c9, c12, 0" :: [v]"r"(v) : ); + } +}; + + +/** + * Interrupt Enable Clear Register + */ +struct Pmintenclr : Register<32> +{ + struct C : Bitfield<31,1> { }; /* disable cycle counter overflow interrupt request */ + struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow interrupt request */ + struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow interrupt reuqest */ + + static access_t disable_overflow_intr() + { + return C::bits(1) | + P0::bits(1) | + P1::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c9, c14, 2" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %[v], c9, c14, 2" :: [v]"r"(v) : ); + } +}; + + +/** + * Count Enable Set Register + */ +struct Pmcntenset : Register<32> +{ + struct C : Bitfield<31,1> { }; /* cycle counter enable */ + struct P0 : Bitfield<0,1> { }; /* counter 0 enable */ + struct P1 : Bitfield<1,1> { }; /* counter 1 enable */ + struct P2 : Bitfield<2,1> { }; /* counter 2 enable */ + struct P3 : Bitfield<3,1> { }; /* counter 3 enable */ + + static access_t enable_counter() + { + return C::bits(1) | + P0::bits(1) | + P1::bits(1) | + P2::bits(1) | + P3::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c9, c12, 1" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %0, c9, c12, 1" :: [v]"r"(v) : ); + } +}; + + +/** + * Overflow Flag Status Register + */ +struct Pmovsr : Register<32> +{ + struct C : Bitfield<31,1> { }; /* cycle counter overflow flag */ + struct P0 : Bitfield<0,1> { }; /* counter 0 overflow flag */ + struct P1 : Bitfield<1,1> { }; /* counter 1 overflow flag */ + + static access_t clear_overflow_flags() + { + return C::bits(1) | + P0::bits(1) | + P1::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c9, c12, 3" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %0, c9, c12, 3" :: [v]"r"(v) : ); + } +}; + + +/** + * User Enable Register + */ +struct Pmuseren : Register<32> +{ + struct En : Bitfield<0,1> { }; /* enable user mode access */ + + static access_t enable() + { + return En::bits(1); + } + + static access_t read() + { + access_t v; + asm volatile("mrc p15, 0, %[v], c9, c14, 0" : [v]"=r"(v) :: ); + return v; + } + + static void write(access_t const v) + { + asm volatile("mcr p15, 0, %0, c9, c14, 0" :: [v]"r"(v) : ); + } +}; + + +void Kernel::Perf_counter::enable() +{ + /* program PMU and enable all counters */ + Pmcr::write(Pmcr::enable_and_reset()); + Pmcntenset::write(Pmcntenset::enable_counter()); + Pmovsr::write(Pmovsr::clear_overflow_flags()); + + /* enable user-mode access to counters and disable overflow interrupt. */ + Pmuseren::write(Pmuseren::enable()); + Pmintenclr::write(Pmintenclr::disable_overflow_intr()); +} + + +Kernel::Perf_counter* Kernel::perf_counter() +{ + static Kernel::Perf_counter inst; + return &inst; +} diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 550545e696..c0cd09a240 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -34,6 +34,7 @@ /* base-hw includes */ #include +#include using namespace Kernel; @@ -955,6 +956,9 @@ extern "C" void kernel() /* TrustZone initialization code */ trustzone_initialization(pic()); + /* enable performance counter */ + perf_counter()->enable(); + /* switch to core address space */ Cpu::init_virt_kernel(core()->tlb()->base(), core_id()); diff --git a/base-hw/src/core/perf_counter.cc b/base-hw/src/core/perf_counter.cc new file mode 100644 index 0000000000..ae11ddc0b0 --- /dev/null +++ b/base-hw/src/core/perf_counter.cc @@ -0,0 +1,25 @@ +/* + * \brief Performance counter dummy + * \author Josef Soentgen + * \date 2013-09-26 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* base-hw includes */ +#include + + +void Kernel::Perf_counter::enable() { } + + +Kernel::Perf_counter* Kernel::perf_counter() +{ + static Kernel::Perf_counter inst; + return &inst; +} diff --git a/base-hw/src/core/target.inc b/base-hw/src/core/target.inc index d5d71d4506..c14aabf0bb 100644 --- a/base-hw/src/core/target.inc +++ b/base-hw/src/core/target.inc @@ -11,7 +11,7 @@ TARGET = core CC_OPT += -DCORE_MAIN=_main # add library dependencies -LIBS += base-common +LIBS += base-common perf_counter # add include paths INC_DIR += $(REP_DIR)/src/core \