imx51-linux的cpuinfo之分析
这两天客户提出来,我们的平板cat /proc/cpuinfo出来的信息中的serial怎么是0.
客户就是上帝啊,没办法,分析找问题贝。
我们先看一下目前的cat /proc/cpuinfo的信息:
Processor : ARMv7 Processor rev 5 (v7l)
BogoMIPS : 799.53
Features : swp half thumb fastmult vfp edsp neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x2
CPU part : 0xc08
CPU revision : 5
Hardware : Freescale MX51 F101 Board
Revision : 51030
Serial : 0000000000000000
我们找到kernel中的cpuinfo的文件,路径在fs/proc/cpuinfo.c 。
我们首先看一下它的init函数:
static int __init proc_cpuinfo_init(void)
{
proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
return 0;
}
嗯,很明星,我们cat /proc/cpuinfo的文件就是在该init中创建的。我们注意到创建该文件时传入了fops。我们再看一下proc_cpuinfo_operations这个fops定义:
static const struct file_operations proc_cpuinfo_operations = {
.open = cpuinfo_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
我们执行cat /proc/cpuinfo时实际就是执行了open和read这两个函数。
我们下面分别分析一下open和read分别做了什么事情。
1,open
open定义如下:
static int cpuinfo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &cpuinfo_op);
}
我们发现调用open的时候传入了cpuinfo_op这个结构。这个结构就是cpuinfo的实际操作方法。这个cpuinfo_op是每种cpu架构都必须特别定义的。我们用的是arm架构,我们找到它的定义:
arch/arm/kernel/setup.c :
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = c_show
};
我们知道这个结构体后,我们继续看open,
int seq_open(struct file *file, const struct seq_operations *op)
{
struct seq_file *p = file->private_data;
if (!p) { //如果file->private_data为空,则为它申请空间
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
file->private_data = p;
}
memset(p, 0, sizeof(*p));//清0
mutex_init(&p->lock); //初始化mutex
p->op = op; //将上面传进来的cpuinfo_op赋值给file
file->f_version = 0;
file->f_mode &= ~FMODE_PWRITE;
return 0;
}
我们看到seq_open的主要作用是将ops保持到file->private_data中。
2,read
我们上面说cat /proc/cpuinfo就相对于执行open和read,我们下面来看看热啊的。
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
struct seq_file *m = (struct seq_file *)file->private_data;//看清楚了,把刚才上面open中的cpuinfo_op取出来了!下面就可以使用这个结构里面的方法了!
size_t copied = 0;
loff_t pos;
size_t n;
void *p;
int err = 0;
mutex_lock(&m->lock);
......
pos = m->index;
p = m->op->start(m, &pos);//执行cpuinfo_op中的start方法
while (1) {
err = PTR_ERR(p);
if (!p || IS_ERR(p))
break;
err = m->op->show(m, p);//执行cpuinfo_op中show方法
if (err < 0)
break;
if (unlikely(err))
m->count = 0;
if (unlikely(!m->count)) {
p = m->op->next(m, p, &pos);
m->index = pos;
continue;
}
if (m->count < m->size)
goto Fill;
m->op->stop(m, p);
kfree(m->buf);
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
if (!m->buf)
goto Enomem;
m->count = 0;
m->version = 0;
pos = m->index;
p = m->op->start(m, &pos);
}
m->op->stop(m, p);
......
}
我们看到read方法中主要执行了cpuinfo_op中方法:
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = c_show
};
我们下面一个一个来分析,
static void *c_start(struct seq_file *m, loff_t *pos)
{
return *pos < 1 ? (void *)1 : NULL;
}
c_start主要验证文件的位置。
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return NULL;
}
c_next移动文件位置的指针,指向下一个。
static void c_stop(struct seq_file *m, void *v)
{
}
c_stop没有做事情。
static int c_show(struct seq_file *m, void *v)
{
int i;
/*打印cpu的processor,例如例子中的Processor : ARMv7 Processor rev 5 (v7l)*/
seq_printf(m, "Processor\t: %s rev %d (%s)\n",
cpu_name, read_cpuid_id() & 15, elf_platform);
#if defined(CONFIG_SMP)//如果是多核处理器,则分别打印cpu的processor信息和主频信息
for_each_online_cpu(i) {
/*
* glibc reads /proc/cpuinfo to determine the number of
* online processors, looking for lines beginning with
* "processor". Give glibc what it expects.
*/
seq_printf(m, "processor\t: %d\n", i);
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
(per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
}
#else /* CONFIG_SMP */
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
loops_per_jiffy / (500000/HZ),
(loops_per_jiffy / (5000/HZ)) % 100);
#endif
/* dump out the processor features */
seq_puts(m, "Features\t: ");//下面打印feature信息
for (i = 0; hwcap_str;
i++)
if (elf_hwcap & (1 << i))
seq_printf(m, "%s ", hwcap_str);
seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
/* pre-ARM7 */
seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
} else {
if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
/* ARM7 */
seq_printf(m, "CPU variant\t: 0x%02x\n",
(read_cpuid_id() >> 16) & 127);
} else {
/* post-ARM7 */
seq_printf(m, "CPU variant\t: 0x%x\n",
(read_cpuid_id() >> 20) & 15);
}
seq_printf(m, "CPU part\t: 0x%03x\n",
(read_cpuid_id() >> 4) & 0xfff);
}
seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
seq_puts(m, "\n");
seq_printf(m, "Hardware\t: %s\n", machine_name);
seq_printf(m, "Revision\t: %04x\n", system_rev);
seq_printf(m, "Serial\t\t: %08x%08x\n",
system_serial_high, system_serial_low);//这里我们终于看到serial打印的地方了。我们发现主要打印 system_serial_high,和system_serial_low两个变量的值。如果没有赋值,则打印0。我们要做的工作就是为这两个变量赋值。
return 0;
}
好了,问题分析差不多了,下面就是实现它。这个值就是cpu的uuid,Unique ID是芯片的唯一的ID,是芯片的产线上的信息。每个芯片都有不同的值,每种芯片都有不一样的方法去读。
我们平板用的是imx51,以imx51为例子,它是通过IIM读Fuse的数据。地址是:(0x83F98000 + 0x820) ~ (0x83F98000 + 0x83C),共8个字节。
具体实现,代码奉上:
在driver/char/mxc_iim.c中的probe加上:
/*via iim, read cpu UID*/
//open iim
iim_data->clk = clk_get(NULL, "iim_clk");
if (IS_ERR(iim_data->clk)) {
dev_err(iim_data->dev, "No IIM clock defined\n");
return -ENODEV;
}
clk_enable(iim_data->clk);
mxc_iim_disable_irq();
//read iim
addr = 0x820; //uid start addr
for(i=0;i<32;i+=4){
bank = (addr + i - iim_data->bank_start) >> 10;
row = ((addr + i - iim_data->bank_start) & 0x3ff) >> 2;
dev_dbg(iim_data->dev, "Read fuse at bank:%d row:%d\n",
bank, row);
mutex_lock(&iim_data->mutex);
fuse_val = sense_fuse(bank, row, 0);
serial[i/4] = fuse_val;
mutex_unlock(&iim_data->mutex);
dev_dbg(iim_data->dev, "fuses at addr0x%x(bank:%d, row:%d) = 0x%x\n",
addr + i, bank, row, fuse_val);
}
system_serial_low = ((serial[3]<<24)&0xff000000) + ((serial[2]<<16)&0x00ff0000) + ((serial[1]<<8)&0x0000ff00) + (serial[0]&0x000000ff);
system_serial_high = ((serial[7]<<24)&0xff000000) + ((serial[6]<<16)&0x00ff0000) + ((serial[5]<<8)&0x0000ff00) + (serial[4]&0x000000ff);
dev_info(iim_data->dev, "system_serial_high:0x%x, system_serial_low:0x%x", system_serial_high, system_serial_low);
OK,至此就非常完美地实现了!
imx51-linux的cpuinfo之分析的更多相关文章
- [转]linux /proc/cpuinfo 文件分析
在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针对该文件进行简单的总结. 基于不同指 ...
- /proc/cpuinfo 文件分析(查看CPU信息)
/proc/cpuinfo文件分析 根据以下内容,我们则可以很方便的知道当前系统关于CPU.CPU的核数.CPU是否启用超线程等信息. <1>查询系统具有多少个逻辑核:cat /proc/ ...
- linux服务器宕机分析/性能瓶颈分析
linux服务器宕机分析/性能瓶颈分析 服务器宕机原因很多,资源不足.应用.硬件.系统内核bug等,以下一个小例子 服务器宕机了,首先得知道服务器宕机的时间点,然后分析日志查找原因 1.last ...
- Android/Linux下CGroup框架分析及其使用
1 cgroup介绍 CGroup是control group的简称,它为Linux kernel提供一种任务聚集和划分的机制,可以限制.记录.隔离进程组(process groups)所使用的资源( ...
- Linux Kernel Oops异常分析
1.PowerPC小系统内核异常分析 1.1 异常打印 Unable to handle kernel paging request for data at address 0x36fef31eFa ...
- 20169212《Linux内核原理与分析》课程总结
20169212<Linux内核原理与分析>课程总结 每周作业链接汇总 第一周作业:完成linux基础入门实验,了解一些基础的命令操作. 第二周作业:学习MOOC课程--计算机是如何工作的 ...
- 1.linux服务器的性能分析与优化
[教程主题]:1.linux服务器的性能分析与优化 [课程录制]: 创E [主要内容] [1]影响Linux服务器性能的因素 操作系统级 CPU 目前大部分CPU在同一时间只能运行一个线程,超线程的处 ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- Linux系统日志及日志分析
Linux系统日志及日志分析 Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息. 大部分Linux发行版默认的日志守护进程为 syslog,位 ...
- 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化
高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...
随机推荐
- CentOS7下安装GitLab
三步在CentOS7系统下,完成GitLab的安装. 1.安装和配置必须的依赖 sudo yum install curl policycoreutils openssh-server openssh ...
- SpringMVC源码分析--文件上传
SpringMVC提供了文件上传的功能,接下来我们就简单了解一下SpringMVC文件上传的开发及大致过程. 首先需要在springMVC的配置文件中配置文件上传解析器 <bean id=&qu ...
- Xcode7.2如何真机调试iOS 9.3的设备
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 本猫的mac系统为10.10,Xcode版本为7.2 本猫将i ...
- 使用github搭建网站
http://blog.csdn.net/pipisorry/article/details/51707366 使用github建站 github设计了Pages功能,允许用户自定义项目首页,用来替代 ...
- 学习TensorFlow,保存学习到的网络结构参数并调用
在深度学习中,不管使用那种学习框架,我们会遇到一个很重要的问题,那就是在训练完之后,如何存储学习到的深度网络的参数?在测试时,如何调用这些网络参数?针对这两个问题,本篇博文主要探索TensorFlow ...
- tomcat集群的failover机制
集群要提供高可用性就必须要有某种机制去保证,常用的机制为failover(故障转移),简单说就是通过一定的heartbeat检测是否有故障,一旦故障发生备份节点则接管故障节点的工作. tomcat使用 ...
- ServletContainerInitializer初始化器
在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能.每个框架 ...
- 【java虚拟机系列】java虚拟机系列之JVM总述
我们知道java之所以能够快速崛起一个重要的原因就是其跨平台性,而跨平台就是通过java虚拟机来完成的,java虚拟机属于java底层的知识范畴,即使你不了解也不会影响绝大部分人从事的java应用层的 ...
- OpenCV特征点检测匹配图像-----添加包围盒
最终效果: 其实这个小功能非常有用,甚至加上只有给人感觉好像人脸检测,目标检测直接成了demo了,主要代码如下: // localize the object std::vector<Point ...
- HTML超链接之伪类注意事项
今天在复习html相关知识的时候发现了一个很常用,却经常被人们所忽略的知识点.那就是超链接伪类的使用.下面我就直接用代码来说明这一切. 伪类的相关代码 <!DOCTYPE html> &l ...