genode/repos/base-hw/src/core/spec/arm_v7/perf_counter.cc

188 lines
4.0 KiB
C++

/*
* \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-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <util/register.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
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()
{
access_t v = 0;
E::set(v, 1);
P::set(v, 1);
C::set(v, 1);
return v;
}
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 IRQ */
struct P0 : Bitfield<0,1> { }; /* disable pmc0 overflow IRQ */
struct P1 : Bitfield<1,1> { }; /* disable pmc1 overflow IRQ */
static access_t disable_overflow_intr()
{
access_t v = 0;
C::set(v, 1) ;
P0::set(v, 1);
P1::set(v, 1);
return v;
}
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()
{
access_t v = 0;
C::set(v, 1);
P0::set(v, 1);
P1::set(v, 1);
P2::set(v, 1);
P3::set(v, 1);
return v;
}
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()
{
access_t v = 0;
C::set(v, 1);
P0::set(v, 1);
P1::set(v, 1);
return v;
}
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;
}