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.
This commit is contained in:
Josef Söntgen 2013-09-26 17:03:33 +02:00 committed by Norman Feske
parent 341290a266
commit afdabe9df8
10 changed files with 388 additions and 1 deletions

View File

@ -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_ */

View File

@ -0,0 +1,3 @@
SRC_CC = perf_counter.cc
vpath %.cc $(REP_DIR)/src/core/arm_v6

View File

@ -0,0 +1,3 @@
SRC_CC = perf_counter.cc
vpath %.cc $(REP_DIR)/src/core/arm_v7

View File

@ -0,0 +1,3 @@
SRC_CC = perf_counter.cc
vpath %.cc $(REP_DIR)/src/core/

View File

@ -0,0 +1 @@
LIBS += enable_perf_counter

View File

@ -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 <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 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;
}

View File

@ -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 <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()
{
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;
}

View File

@ -34,6 +34,7 @@
/* base-hw includes */
#include <singleton.h>
#include <kernel/perf_counter.h>
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());

View File

@ -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 <kernel/perf_counter.h>
void Kernel::Perf_counter::enable() { }
Kernel::Perf_counter* Kernel::perf_counter()
{
static Kernel::Perf_counter inst;
return &inst;
}

View File

@ -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 \