gpt4 book ai didi

linux - ARM Cortex A7 在内核模式下返回 PMCCNTR = 0,在用户模式下返回非法指令(即使在 PMUSERENR = 1 之后)

转载 作者:IT王子 更新时间:2023-10-29 01:00:34 25 4
gpt4 key购买 nike

我想读取具有 ARM Cortex A7 内核的 Raspberry Pi 2 上的周期计数寄存器 (PMCCNTR)。我为它编译了一个内核模块如下:

#include <linux/module.h>
#include <linux/kernel.h>

int init_module()
{
volatile u32 PMCR, PMUSERENR, PMCCNTR;

// READ PMCR
PMCR = 0xDEADBEEF;
asm volatile ("mrc p15, 0, %0, c9, c12, 0\n\t" : "=r" (PMCR));
printk (KERN_INFO "PMCR = %x\n", PMCR);

// READ PMUSERENR
PMUSERENR = 0xDEADBEEF;
asm volatile ("mrc p15, 0, %0, c9, c14, 0\n\t" : "=r" (PMUSERENR));
printk (KERN_INFO "PMUSERENR = %x\n", PMUSERENR);

// WRITE PMUSERENR = 1
asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" : : "r" (1));

// READ PWMUSERENR AGAIN
asm volatile ("mrc p15, 0, %0, c9, c14, 0\n\t" : "=r" (PMUSERENR));
printk (KERN_INFO "PMUSERENR = %x\n", PMUSERENR);

// READ PMCCNTR
PMCCNTR = 0xDEADBEEF;
asm volatile ("mrc p15, 0, %0, c9, c13, 0\n\t" : "=r" (PMCCNTR));
printk (KERN_ALERT "PMCCNTR = %x\n", PMCCNTR);
return 0;
}

void cleanup_module()
{
}

MODULE_LICENSE("GPL");

并且,在 insmod 之后,我在 /var/log/kern.log 中观察到以下内容:

PMCR = 41072000
PMUSERENR = 0
PMUSERENR = 1
PMCCNTR = 0

当我尝试从用户模式读取 PMCCNTR 时,我得到了非法指令,即使 PMUSERENR 已设置为 1。

为什么 PMCCNTR 在内核态读为 0,而在用户态读为非法指令?为了启用 PMCCNTR,是否还有其他我需要做但我没有做的事情?

更新1

部分解决。多核问题的解决方案是像这样调用on_each_cpu:

#include <linux/module.h>
#include <linux/kernel.h>

static void enable_ccnt_read(void* data)
{
// WRITE PMUSERENR = 1
asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" : : "r" (1));
}

int init_module()
{
on_each_cpu(enable_ccnt_read, NULL, 1);
return 0;
}

void cleanup_module()
{
}

MODULE_LICENSE("GPL");

我现在可以从用户区读取 PMCCNTR:

#include <iostream>

unsigned ccnt_read ()
{
volatile unsigned cc;
asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r" (cc));
return cc;
}

int main() {
std::cout << ccnt_read() << std::endl;
}

要在特定内核上运行用户空间程序,您可以像这样使用taskset(例如,在内核 2 上运行):

$ taskset -c 2 ./ccnt_read
0

PMCCNTR 仍然没有递增。它们需要以某种方式“开启”。

最佳答案

这是后代的工作解决方案:

内核模块:

#include <linux/module.h>
#include <linux/kernel.h>

static void enable_ccnt_read(void* data)
{
// PMUSERENR = 1
asm volatile ("mcr p15, 0, %0, c9, c14, 0" :: "r"(1));

// PMCR.E (bit 0) = 1
asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(1));

// PMCNTENSET.C (bit 31) = 1
asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(1 << 31));
}

int init_module()
{
on_each_cpu(enable_ccnt_read, NULL, 1);
return 0;
}

void cleanup_module()
{
}

MODULE_LICENSE("GPL");

客户端程序:

#include <iostream>

unsigned ccnt_read ()
{

volatile unsigned cc;
asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r" (cc));
return cc;
}

int main() {
std::cout << ccnt_read() << std::endl;
}

关于linux - ARM Cortex A7 在内核模式下返回 PMCCNTR = 0,在用户模式下返回非法指令(即使在 PMUSERENR = 1 之后),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31620375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com