这两天客户提出来,我们的平板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之分析相关推荐

  1. linux 下/proc/cpuinfo三级缓存,linux /proc/cpuinfo文件分析

    基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含如下内容: processor : 0 vendor_id :Ge ...

  2. linux /proc/cpuinfo文件分析

    为什么80%的码农都做不了架构师?>>>    基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含 ...

  3. linux下/proc/cpuinfo 文件分析

    /proc/cpuinfo文件分析 在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针 ...

  4. linux服务器宕机分析/性能瓶颈分析

    linux服务器宕机分析/性能瓶颈分析 服务器宕机原因很多,资源不足.应用.硬件.系统内核bug等,以下一个小例子 服务器宕机了,首先得知道服务器宕机的时间点,然后分析日志查找原因 1.last re ...

  5. 常用Linux网络/内存/磁盘分析工具

    Centos查看网卡.CPU.内存等使用率 # watch more /proc/net/dev 性能分析和监控工具 uptime dmesg | tail vmstat 1 mpstat -P AL ...

  6. linux内核时钟管理,Linux时钟管理透彻分析

    Linux时钟管理透彻分析.硬件资源越来越庞大和复杂,内核的另一个挑战就是要便捷的管理这些资源.同时,面对如此之多的平台不同的CPU,管理机制需要统一适用,这就需要对资源的管理抽象到更加通用的层次.C ...

  7. 一次Linux系统被***的分析过程

    IT行业发展到现在,安全问题已经变得至关重要,从最近的"棱镜门"事件中,折射出了很多安全问题,信息安全问题已变得刻不容缓,而做为运维人员,就必须了解一些安全运维准则,同时,要保护自 ...

  8. linux内存源码分析 - 内存压缩(同步关系)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也 ...

  9. 基于Linux系统中进程调度分析

    本文作者(院 浩),请您在阅读本文时尊重作者版权. [摘要]Linux是一个多用户多任务的操作系统,Linux中实现了对多个进程公平.高效的调度,并不是采用单一的调度策略,而是几种调度策略有机地综合应 ...

  10. 基于linux服务器的性能分析与优化

    基于linux服务器的性能分析与优化 方面:硬件系统软件网络 现象:系统不稳定相应速度慢 web无法打开打开速度慢 方案:硬件故障更换硬件或升级硬件 系统问题修改系统参数和配置 软件问题修改和升级软件 ...

最新文章

  1. 计算机网络管理的常用命令,网络管理常用命令图文详解.pdf
  2. 这样的烂代码,我实习的时候都写不出来!
  3. python urllib2下载文件 是否成功,Python urllib2未完成下载fi
  4. Codeforces - 466C - Number of Ways - 组合数学
  5. matlab运行支持向量机不出f,求助各位大神关于libsvm,svmpredict总是出不来结果,调试了好久还是不行...
  6. 谈谈你对oracle的认识,对Oracle存储过程的几点认识
  7. vue2 watch引用类型 失败原因
  8. java实现把数据写入到Excel并下载
  9. Z-blog拓源纯净主题
  10. 优美的 Python
  11. Python入门--文件的读写
  12. char* str = abc ;跟char str[] = abc;的区别
  13. Python 技巧总结
  14. cboard企业版源码_Cboard 搭建和初步试用文档
  15. windows64位PowerDesigner下载
  16. ImportError: cannot import name ‘chatBot‘ from ‘chatbot‘ (C:\Users\l\Pych
  17. 求数组内子数组最大的和(Maximum Subarray )
  18. OpenGL实现在三维空间拖拽物体
  19. 安装虚拟机(VMware)保姆级教程(附安装包)
  20. 对于SDL中colorkey的理解

热门文章

  1. 28和lba48命令格式区别_linux硬盘分区、格式化、挂载超详细步骤
  2. .net mvc actionresult 返回字符串_字符串游戏之无效的身份证
  3. Java中基本数据类型和Object之间的关系
  4. 024_Jedis连接池
  5. JAVA数据库第四章上机3_Java第二至第四章上机练习题
  6. 安徽工业大学计算机考研调剂,安徽工业大学2019年考研预调剂公告
  7. 谷歌浏览器禁止右滑返回历史_移动端h5禁用浏览器左滑右滑的前进后退功能
  8. Facebook-Rebound探索发现
  9. RecyclerView的优化:RecycledViewPool
  10. 你的气质里藏着 英文_有小肚腩女人穿衣要讲究,针织套装裙洋气又时髦,穿出优雅气质...