summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2005-04-28 08:13:19 +0000
committerjkoshy <jkoshy@FreeBSD.org>2005-04-28 08:13:19 +0000
commitcb5a9ccd732dad2fb703d20cb1775266c9a916df (patch)
tree6d64ad42ff8aec2fef5909520668bd5172f0949c /sys
parentb38862d9b3350743b801238ea0108b7ae70baabf (diff)
downloadFreeBSD-src-cb5a9ccd732dad2fb703d20cb1775266c9a916df.zip
FreeBSD-src-cb5a9ccd732dad2fb703d20cb1775266c9a916df.tar.gz
Return the correct register number in the 'get_msr()' MD function.
Only allow a process to use the x86 RDPMC instruction if it has allocated and attached a PMC to itself. Inform the MD layer of the "pseudo context switch out" that needs to be done when the last thread of a process is exiting.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/hwpmc/hwpmc_amd.c27
-rw-r--r--sys/dev/hwpmc/hwpmc_mod.c31
-rw-r--r--sys/dev/hwpmc/hwpmc_piv.c28
-rw-r--r--sys/dev/hwpmc/hwpmc_ppro.c13
-rw-r--r--sys/i386/include/pmc_mdep.h3
-rw-r--r--sys/sys/pmc.h16
6 files changed, 89 insertions, 29 deletions
diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c
index a78943a..158dc0b 100644
--- a/sys/dev/hwpmc/hwpmc_amd.c
+++ b/sys/dev/hwpmc/hwpmc_amd.c
@@ -443,6 +443,8 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm)
{
struct pmc_hw *phw;
+ PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
KASSERT(cpu >= 0 && cpu < mp_ncpus,
("[amd,%d] illegal CPU value %d", __LINE__, cpu));
KASSERT(ri >= 0 && ri < AMD_NPMCS,
@@ -451,7 +453,8 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm)
phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
KASSERT(pm == NULL || phw->phw_pmc == NULL,
- ("[amd,%d] hwpmc not unconfigured before re-config", __LINE__));
+ ("[amd,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
+ __LINE__, pm, phw->phw_pmc));
phw->phw_pmc = pm;
return 0;
@@ -463,12 +466,17 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm)
*/
static int
-amd_switch_in(struct pmc_cpu *pc)
+amd_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
- /* enable the RDPMC instruction */
- load_cr4(rcr4() | CR4_PCE);
+ PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp,
+ (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0);
+
+ /* enable the RDPMC instruction if needed */
+ if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS)
+ load_cr4(rcr4() | CR4_PCE);
+
return 0;
}
@@ -478,12 +486,17 @@ amd_switch_in(struct pmc_cpu *pc)
*/
static int
-amd_switch_out(struct pmc_cpu *pc)
+amd_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
+ (void) pp; /* can be NULL */
- /* disallow RDPMC instruction */
+ PMCDBG(MDP,SWO,1, "pc=%p pp=%p enable-msr=%d", pc, pp, pp ?
+ (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) == 1 : 0);
+
+ /* always turn off the RDPMC instruction */
load_cr4(rcr4() & ~CR4_PCE);
+
return 0;
}
@@ -818,7 +831,7 @@ amd_get_msr(int ri, uint32_t *msr)
KASSERT(ri >= 0 && ri < AMD_NPMCS,
("[amd,%d] ri %d out of range", __LINE__, ri));
- *msr = amd_pmcdesc[ri].pm_perfctr;
+ *msr = amd_pmcdesc[ri].pm_perfctr - AMD_PMC_PERFCTR_0;
return 0;
}
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index 3f5cbd7..00cf9fa 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -739,8 +739,13 @@ pmc_link_target_process(struct pmc *pm, struct pmc_process *pp)
atomic_store_rel_ptr(&pp->pp_pmcs[ri].pp_pmc, pm);
+ if (pm->pm_owner->po_owner == pp->pp_proc)
+ pp->pp_flags |= PMC_FLAG_ENABLE_MSR_ACCESS;
+
pp->pp_refcnt++;
+ PMCDBG(PRC,TLK,2, "enable-msr %d",
+ (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0);
}
/*
@@ -774,6 +779,9 @@ pmc_unlink_target_process(struct pmc *pm, struct pmc_process *pp)
pp->pp_pmcs[ri].pp_pmc = NULL;
pp->pp_pmcs[ri].pp_pmcval = (pmc_value_t) 0;
+ if (pm->pm_owner->po_owner == pp->pp_proc)
+ pp->pp_flags &= ~PMC_FLAG_ENABLE_MSR_ACCESS;
+
pp->pp_refcnt--;
/* Remove the target process from the PMC structure */
@@ -784,7 +792,8 @@ pmc_unlink_target_process(struct pmc *pm, struct pmc_process *pp)
KASSERT(ptgt != NULL, ("[pmc,%d] process %p (pp: %p) not found "
"in pmc %p", __LINE__, pp->pp_proc, pp, pm));
- PMCDBG(PRC,TUL,4, "unlink ptgt=%p", ptgt);
+ PMCDBG(PRC,TUL,4, "unlink ptgt=%p, enable-msr=%d", ptgt,
+ (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0);
LIST_REMOVE(ptgt, pt_next);
FREE(ptgt, M_PMC);
@@ -1159,10 +1168,10 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
"process-exit proc=%p pmc-process=%p", p, pp);
/*
- * This process could the target of some PMCs.
- * Such PMCs will thus be running on currently
- * executing CPU at this point in the code
- * since we've disallowed context switches.
+ * The exiting process could the target of
+ * some PMCs which will be running on
+ * currently executing CPU.
+ *
* We need to turn these PMCs off like we
* would do at context switch OUT time.
*/
@@ -1219,6 +1228,14 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
atomic_subtract_rel_32(&pm->pm_runcount,1);
(void) md->pmd_config_pmc(cpu, ri, NULL);
}
+
+ /*
+ * Inform the MD layer of this pseudo "context switch
+ * out"
+ */
+
+ (void) md->pmd_switch_out(pmc_pcpu[cpu], pp);
+
critical_exit(); /* ok to be pre-empted now */
/*
@@ -1475,7 +1492,7 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
* switch-in actions.
*/
- (void) (*md->pmd_switch_in)(pc);
+ (void) (*md->pmd_switch_in)(pc, pp);
critical_exit();
@@ -1614,7 +1631,7 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
* switch out functions.
*/
- (void) (*md->pmd_switch_out)(pc);
+ (void) (*md->pmd_switch_out)(pc, pp);
critical_exit();
diff --git a/sys/dev/hwpmc/hwpmc_piv.c b/sys/dev/hwpmc/hwpmc_piv.c
index de2ad70..67be026 100644
--- a/sys/dev/hwpmc/hwpmc_piv.c
+++ b/sys/dev/hwpmc/hwpmc_piv.c
@@ -578,11 +578,19 @@ p4_cleanup(int cpu)
*/
static int
-p4_switch_in(struct pmc_cpu *pc)
+p4_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
+
+ PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp,
+ (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0);
+
/* enable the RDPMC instruction */
- load_cr4(rcr4() | CR4_PCE);
+ if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS)
+ load_cr4(rcr4() | CR4_PCE);
+
+ PMCDBG(MDP,SWI,2, "cr4=0x%x", rcr4());
+
return 0;
}
@@ -591,11 +599,18 @@ p4_switch_in(struct pmc_cpu *pc)
*/
static int
-p4_switch_out(struct pmc_cpu *pc)
+p4_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
- /* disallow RDPMC instruction */
+ (void) pp; /* can be null */
+
+ PMCDBG(MDP,SWO,1, "pc=%p pp=%p", pc, pp);
+
+ /* always disallow the RDPMC instruction */
load_cr4(rcr4() & ~CR4_PCE);
+
+ PMCDBG(MDP,SWO,2, "cr4=0x%x", rcr4());
+
return 0;
}
@@ -1419,7 +1434,10 @@ p4_get_msr(int ri, uint32_t *msr)
KASSERT(ri >= 0 && ri < P4_NPMCS,
("[p4,%d] ri %d out of range", __LINE__, ri));
- *msr = p4_pmcdesc[ri].pm_pmc_msr;
+ *msr = p4_pmcdesc[ri].pm_pmc_msr - P4_PERFCTR_MSR_FIRST;
+
+ PMCDBG(MDP,OPS, 1, "ri=%d getmsr=0x%x", ri, *msr);
+
return 0;
}
diff --git a/sys/dev/hwpmc/hwpmc_ppro.c b/sys/dev/hwpmc/hwpmc_ppro.c
index c08c509..1bd19be6 100644
--- a/sys/dev/hwpmc/hwpmc_ppro.c
+++ b/sys/dev/hwpmc/hwpmc_ppro.c
@@ -332,16 +332,25 @@ p6_cleanup(int cpu)
}
static int
-p6_switch_in(struct pmc_cpu *pc)
+p6_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
+
+ /* allow the RDPMC instruction if needed */
+ if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS)
+ load_cr4(rcr4() | CR4_PCE);
return 0;
}
static int
-p6_switch_out(struct pmc_cpu *pc)
+p6_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
{
(void) pc;
+ (void) pp; /* can be NULL */
+
+ /* always turn off the RDPMC instruction */
+ load_cr4(rcr4() & ~CR4_PCE);
+
return 0;
}
diff --git a/sys/i386/include/pmc_mdep.h b/sys/i386/include/pmc_mdep.h
index 84f75d7..8b25e1e 100644
--- a/sys/i386/include/pmc_mdep.h
+++ b/sys/i386/include/pmc_mdep.h
@@ -123,6 +123,9 @@
#define P4_PERFCTR_MASK 0xFFFFFFFFFFLL /* 40 bits */
+#define P4_CCCR_MSR_FIRST 0x360 /* MSR_BPU_CCCR0 */
+#define P4_PERFCTR_MSR_FIRST 0x300 /* MSR_BPU_COUNTER0 */
+
/* Intel PPro, Celeron, P-II, P-III, Pentium-M PMCS */
#define P6_NPMCS 3 /* 1 TSC + 2 PMCs */
diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h
index b2a3479..76baa16 100644
--- a/sys/sys/pmc.h
+++ b/sys/sys/pmc.h
@@ -1158,6 +1158,7 @@ struct pmc_targetstate {
struct pmc_process {
LIST_ENTRY(pmc_process) pp_next; /* hash chain */
int pp_refcnt; /* reference count */
+ uint32_t pp_flags; /* flags */
struct proc *pp_proc; /* target thread */
struct pmc_targetstate pp_pmcs[]; /* NHWPMCs */
};
@@ -1183,9 +1184,10 @@ struct pmc_owner {
int po_logfd; /* XXX for now */
};
-#define PMC_FLAG_IS_OWNER 0x01
-#define PMC_FLAG_HAS_TS_PMC 0x02
-#define PMC_FLAG_OWNS_LOGFILE 0x04 /* owns system-sampling log file */
+#define PMC_FLAG_IS_OWNER 0x01
+#define PMC_FLAG_HAS_TS_PMC 0x02
+#define PMC_FLAG_OWNS_LOGFILE 0x04
+#define PMC_FLAG_ENABLE_MSR_ACCESS 0x08
/*
* struct pmc_hw -- describe the state of the PMC hardware
@@ -1283,11 +1285,9 @@ struct pmc_mdep {
int (*pmd_init)(int _cpu); /* machine dependent initialization */
int (*pmd_cleanup)(int _cpu); /* machine dependent cleanup */
- /* thread context switch in */
- int (*pmd_switch_in)(struct pmc_cpu *_p);
-
- /* thread context switch out */
- int (*pmd_switch_out)(struct pmc_cpu *_p);
+ /* thread context switch in/out */
+ int (*pmd_switch_in)(struct pmc_cpu *_p, struct pmc_process *_pp);
+ int (*pmd_switch_out)(struct pmc_cpu *_p, struct pmc_process *_pp);
/* configuring/reading/writing the hardware PMCs */
int (*pmd_config_pmc)(int _cpu, int _ri, struct pmc *_pm);
OpenPOWER on IntegriCloud