这两天客户提出来,我们的平板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文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针对该文件进行简单的总结. 基于不同指 ...

  2. /proc/cpuinfo 文件分析(查看CPU信息)

    /proc/cpuinfo文件分析 根据以下内容,我们则可以很方便的知道当前系统关于CPU.CPU的核数.CPU是否启用超线程等信息. <1>查询系统具有多少个逻辑核:cat /proc/ ...

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

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

  4. Android/Linux下CGroup框架分析及其使用

    1 cgroup介绍 CGroup是control group的简称,它为Linux kernel提供一种任务聚集和划分的机制,可以限制.记录.隔离进程组(process groups)所使用的资源( ...

  5. Linux Kernel Oops异常分析

    1.PowerPC小系统内核异常分析 1.1  异常打印 Unable to handle kernel paging request for data at address 0x36fef31eFa ...

  6. 20169212《Linux内核原理与分析》课程总结

    20169212<Linux内核原理与分析>课程总结 每周作业链接汇总 第一周作业:完成linux基础入门实验,了解一些基础的命令操作. 第二周作业:学习MOOC课程--计算机是如何工作的 ...

  7. 1.linux服务器的性能分析与优化

    [教程主题]:1.linux服务器的性能分析与优化 [课程录制]: 创E [主要内容] [1]影响Linux服务器性能的因素 操作系统级 CPU 目前大部分CPU在同一时间只能运行一个线程,超线程的处 ...

  8. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  9. Linux系统日志及日志分析

    Linux系统日志及日志分析   Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息. 大部分Linux发行版默认的日志守护进程为 syslog,位 ...

  10. 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化

    高性能Linux服务器 第10章    基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...

随机推荐

  1. OpenCV+VS2013 属性表配置

    简介 计算机视觉任务越来越多的依赖著名的开源计算机视觉库OpenCV.OpenCV 2.0 包含了一系列精心设计数据结构和经过优化的视觉算法,大家可以短时间内开发一个不错的视觉应用.OpenCV支持多 ...

  2. APP自动化框架LazyAndroid使用手册(4)--测试模板工程详解

    概述 前面的3篇博文分别对lazyAndroid的框架简介.元素抓取和核心API进行了说明,本文将基于框架给出的测试模板工程,详细阐述下使用该框架进行安卓UI自动化测试的步骤. 模板工程 先来看一下模 ...

  3. Linux内核中的有关Page的算法

    static inline int get_order(unsigned long size) { int order; size = (size-1) >> (PAGE_SHIFT-1) ...

  4. Android源码浅析(六)——SecureCRT远程连接Linux,配置端点和字节码

    Android源码浅析(六)--SecureCRT远程连接Linux,配置端点和字节码 需要编译源码的同学,一般都是win+虚拟机吧,但是再虚拟机里体验并不是很好,所有市面上有很多的软件能够做到在wi ...

  5. Scikit-learn:模型评估Model evaluation

    http://blog.csdn.net/pipisorry/article/details/52250760 模型评估Model evaluation: quantifying the qualit ...

  6. socket系列之什么是socket

    1.什么是socket Socket是应用层与TCP/IP协议族通信的中间抽象层,它是一组接口,应用层通过调用这些接口实现发送和接收数据.一般这种抽象层由操作系统提供或者由JVM自己实现.使用sock ...

  7. sybase isql命令参数详解

    isql 实用工具使您得以输入 Transact-SQL 语句.系统过程和脚本文件. 语法 isql [-?] | [-L] | [ { {-U login_id [-P password]} | - ...

  8. SSH网上商城---商品详情页的制作

    在前面的博文中,小编分别简单的介绍了邮件的发送以及邮件的激活,逛淘宝的小伙伴都有这样的体会,比如在搜索框中输入连衣裙这个商品的时候,会出现多种多样各种款式的连衣裙,连衣裙的信息包括价格,多少人购买,商 ...

  9. iOS10软件崩溃 Xcode8崩溃 打印/字体等问题汇总 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博!iOS开发者交流QQ群: 446310206 [1].Xcode8代码出现ubsystem: com.apple.U ...

  10. Swift基础之Animation动画研究

    最近研究了一下,Swift语言中关于Animation动画的实现学习,分两次进行相关内容的讲解 用表格列出各种动画情况 Demo首页显示展示了一种动画显示方式,代码如下: //绘画装饰    func ...