mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-11 20:01:48 +00:00
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:
committed by
Norman Feske
parent
341290a266
commit
afdabe9df8
31
base-hw/include/kernel/perf_counter.h
Normal file
31
base-hw/include/kernel/perf_counter.h
Normal 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_ */
|
3
base-hw/lib/mk/arm_v6/enable_perf_counter.mk
Normal file
3
base-hw/lib/mk/arm_v6/enable_perf_counter.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
SRC_CC = perf_counter.cc
|
||||||
|
|
||||||
|
vpath %.cc $(REP_DIR)/src/core/arm_v6
|
3
base-hw/lib/mk/arm_v7/enable_perf_counter.mk
Normal file
3
base-hw/lib/mk/arm_v7/enable_perf_counter.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
SRC_CC = perf_counter.cc
|
||||||
|
|
||||||
|
vpath %.cc $(REP_DIR)/src/core/arm_v7
|
3
base-hw/lib/mk/perf_counter.mk
Normal file
3
base-hw/lib/mk/perf_counter.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
SRC_CC = perf_counter.cc
|
||||||
|
|
||||||
|
vpath %.cc $(REP_DIR)/src/core/
|
1
base-hw/lib/mk/perf_counter/perf_counter.mk
Normal file
1
base-hw/lib/mk/perf_counter/perf_counter.mk
Normal file
@ -0,0 +1 @@
|
|||||||
|
LIBS += enable_perf_counter
|
125
base-hw/src/core/arm_v6/perf_counter.cc
Normal file
125
base-hw/src/core/arm_v6/perf_counter.cc
Normal 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;
|
||||||
|
}
|
192
base-hw/src/core/arm_v7/perf_counter.cc
Normal file
192
base-hw/src/core/arm_v7/perf_counter.cc
Normal 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;
|
||||||
|
}
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
/* base-hw includes */
|
/* base-hw includes */
|
||||||
#include <singleton.h>
|
#include <singleton.h>
|
||||||
|
#include <kernel/perf_counter.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
@ -955,6 +956,9 @@ extern "C" void kernel()
|
|||||||
/* TrustZone initialization code */
|
/* TrustZone initialization code */
|
||||||
trustzone_initialization(pic());
|
trustzone_initialization(pic());
|
||||||
|
|
||||||
|
/* enable performance counter */
|
||||||
|
perf_counter()->enable();
|
||||||
|
|
||||||
/* switch to core address space */
|
/* switch to core address space */
|
||||||
Cpu::init_virt_kernel(core()->tlb()->base(), core_id());
|
Cpu::init_virt_kernel(core()->tlb()->base(), core_id());
|
||||||
|
|
||||||
|
25
base-hw/src/core/perf_counter.cc
Normal file
25
base-hw/src/core/perf_counter.cc
Normal 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;
|
||||||
|
}
|
@ -11,7 +11,7 @@ TARGET = core
|
|||||||
CC_OPT += -DCORE_MAIN=_main
|
CC_OPT += -DCORE_MAIN=_main
|
||||||
|
|
||||||
# add library dependencies
|
# add library dependencies
|
||||||
LIBS += base-common
|
LIBS += base-common perf_counter
|
||||||
|
|
||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core \
|
INC_DIR += $(REP_DIR)/src/core \
|
||||||
|
Reference in New Issue
Block a user