全面解析Linux 内核 3.10.x - 板级初始化 - setup_arch_linux 中ckseg1addr函数_Keven2116的博客-程序员资料

技术标签: 架构  kernel  全面解析Linux内核3.10.x  linux  

From: 全面解析Linux 内核 3.10.x - 本文章完全基于MIPS架构

九层之台,起于垒土 千里之行,始于足下 - 老子

从dmesg的第一条打印信息说起 - Linux banner

且看我的ubuntu 12.04的第一条打印语句

Linux version 3.11.0-15-generic ([email protected]) (gcc version 4.6.3 (Ubuntu/
Linaro 4.6.3-1ubuntu5) ) #25~precise1-Ubuntu SMP Thu Jan 30 17:39:31 UTC 2014 
(Ubuntu 3.11.0-15.25~precise1-generic 3.11.10)

内核代码:

printk(KERN_NOTICE "%s", linux_banner);

linux_banner 是个变长buff位于init/version.c文件

const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

宏的内容位于 include/generated/compile.h

Note: compile.h文件是编译生成的,并不属于内核源码!

我叫Mips,可他们都是x86 - setup_arch

不管是移动端,桌面还是服务器市场上,x86独秀一枝花,MIPS系列的CPU都很孤单!曾今的耀眼到如今的孤单,像是看破了人世间的种种! 网络关于这部分基本都是x86 或者 ARM为主的内容,那么我就来说说MIPS吧!

setup_arch
函数做的事情(MIPS,x86,ARM)根据体系架构的不同,初始化也有所不同!
Mips:

void __init setup_arch(char **cmdline_p)
{
    cpu_probe();
    prom_init();

    #ifdef CONFIG_EARLY_PRINTK
    setup_early_printk();
    #endif
    cpu_report();
    check_bugs_early();

    #if defined(CONFIG_VT)
    #if defined(CONFIG_VGA_CONSOLE)
    conswitchp = &vga_con;
    #elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
    #endif
    #endif
    arch_mem_init(cmdline_p);

    resource_init();
    plat_smp_setup();

    cpu_cache_init();
}
总结,setup_arch做了以下几件事情:
1.CPU配置初始化 - cpu_probe()
    __cpuinit void cpu_probe(void)
    {
        struct cpuinfo_mips *c = &current_cpu_data;
        unsigned int cpu = smp_processor_id();  #1.读取CP0(协处理器0的PRId($15)寄存器获取版本号

        c->processor_id = PRID_IMP_UNKNOWN;
        c->fpu_id   = FPIR_IMP_NONE;
        c->cputype  = CPU_UNKNOWN;

        c->processor_id = read_c0_prid();
        switch (c->processor_id & 0xff0000) {
        case PRID_COMP_LEGACY:
            cpu_probe_legacy(c, cpu);
            break;
        case PRID_COMP_MIPS:
            cpu_probe_mips(c, cpu);
            break;
        case PRID_COMP_ALCHEMY:
            cpu_probe_alchemy(c, cpu);
            break;
        case PRID_COMP_SIBYTE:
            cpu_probe_sibyte(c, cpu);
            break;
        case PRID_COMP_BROADCOM:
            cpu_probe_broadcom(c, cpu);
            break;
        case PRID_COMP_SANDCRAFT:
            cpu_probe_sandcraft(c, cpu);
            break;
        case PRID_COMP_NXP:
            cpu_probe_nxp(c, cpu);
            break;
        case PRID_COMP_CAVIUM:
            cpu_probe_cavium(c, cpu);
            break;
        case PRID_COMP_INGENIC:
            cpu_probe_ingenic(c, cpu);
            break;
        case PRID_COMP_NETLOGIC:
            cpu_probe_netlogic(c, cpu);
            break;
    }

    BUG_ON(!__cpu_name[cpu]);
    BUG_ON(c->cputype == CPU_UNKNOWN);

    /*
     * Platform code can force the cpu type to optimize code
     * generation. In that case be sure the cpu type is correctly
     * manually setup otherwise it could trigger some nasty bugs.
     */
    BUG_ON(current_cpu_type() != c->cputype);

    if (mips_fpu_disabled)
        c->options &= ~MIPS_CPU_FPU;

    if (mips_dsp_disabled)
        c->ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P);

    if (c->options & MIPS_CPU_FPU) {
        c->fpu_id = cpu_get_fpu_id();

        if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
            c->isa_level == MIPS_CPU_ISA_M32R2 ||
            c->isa_level == MIPS_CPU_ISA_M64R1 ||
            c->isa_level == MIPS_CPU_ISA_M64R2) {
            if (c->fpu_id & MIPS_FPIR_3D)
                c->ases |= MIPS_ASE_MIPS3D;
        }
    }

    if (cpu_has_mips_r2) {
        c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
        /* R2 has Performance Counter Interrupt indicator */
        c->options |= MIPS_CPU_PCI;
    }
    else
        c->srsets = 1;

    cpu_probe_vmbits(c);

#ifdef CONFIG_64BIT
    if (cpu == 0)
        __ua_limit = ~((1ull << cpu_vmbits) - 1);
#endif
}

通过上面代码,可得知:
1>此函数先是读取协处理器0中处理器ID(PRId)寄存器获取版本后,进行对应CPU的处理!

          +----------------+----------------+----------------+----------------+
          | Company Options| Company ID     | Processor ID   | Revision       |
          +----------------+----------------+----------------+----------------+
           31            24 23            16 15             8 7
                            图1  协处理器0 PRId寄存器

2>获取之后,根据厂商信息进行cpu_probe_xxxx()函数
此函数分两部分:
第一主要通过decode_configs()函数通过协处理器0的 16(Config), 18(WatchLo),$19(WatchHi)寄存器对CPU进行,如图2,图3!

      +----+------+------+----+----+----+----+----+----+----+----+----+---+-----+----+----+----+----+----+
      | CM | EC   | EP   | SB | SS | SW | EW | SC | SM | BE | EM | EB | 0 | IC  | DC | IB | DB | CU | KO |
      +----+------+------+----+----+----+----+----+----+----+----+----+---+-----+----+----+----+----+----+
       31  30   28 27  24  23 22  21 20   19 18  17 16   15   14   13   12 11  9 8   6  5   4    3  2    0
                                    图2  Config 寄存器
                          +----------------+-------+-----+---------+
                          | MatchAddr      | 0     | R   | W       |
                          +----------------+-------+-----+---------+
                           31            3    2       1       0      
                                    图3 WatchLo/Hi 寄存器
Config寄存器主要设置的Bit是
WatchLo/Hi寄存器主要去设置的Bit是

第二根据厂商信息确定CPU_TYPE,确定指令level,确定tlbsize大小!
对于此部分并不是每个人都需要去了解的,有兴趣的可以See 下面的链接!

1.协处理器0,MIPS控制处理器详解

2.简单配置MMU以及获取基地址初始化 - [prom_init]()

    void __init prom_init(void)
    {
        nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE);
        xlp_mmu_init();
        nlm_node_init(0);

    #ifdef CONFIG_SMP
        cpumask_setall(&nlm_cpumask);
        nlm_wakeup_secondary_cpus();

        /* update TLB size after waking up threads */
        current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;

        register_smp_ops(&nlm_smp_ops);
    #endif
    }

上述xlp_mmu_init函数开启了外部TLB,通过已知的页表大小配置得到页掩码,来而新刷新TLB!
之后紧接着又获取了一些基地址信息!
关于MMU以及TLB,请戳这里MIPS- TLB介绍

3.printk console - setup_early_printk

printk console注册流程

void __init setup_early_printk(void)
{
    if (early_console)
        return;
    early_console = &early_console_prom;

    register_console(&early_console_prom);
}

上述代码就是要printk 可以将信息打印早当前的console上,如果有兴趣研究console的工作流程,推荐查看Documentation/coonsole/console.txt

4.打印CPU版本以及FPU版本信息 - cpu_report

因为之前在cpu_probe的时候就已经将相关信息保存到cpuinfo_mips结构体中,在此处将CPU/FPU ID以及name打印出来!

5. 检查多线程 - cpu_chechbugs

此处一般检查

6. VGA初始化

因为当前没有配置CONFIG_VGA_CONSOLE此宏,故而此处跳过!

7. 板级内存初始化 -arch_mem_init

其实这里叫板级内存初始化有点牵强,此处其实做了好几件事情!
在当前版本中,此函数主要做了4件事!
a.打印内存映射 - print_memory_map
b.引导内存分配器进行初始化- bootmem_init
要弄清楚上述两个问题需要结合架构进行分析,先来了解下MIPS的地址空间以及映射关系,请分别戳
c.Device Tree 结构初始化 - device_tree_init
何谓DTS,我这里总结了一篇总结,请戳 全面解析Linux 内核 3.10.x - Device Tree 详解
d.页表初始化
关于页表以及页框等内容我页将其专门总结到一起!戳

8. CPU Cache初始化 - cpu_cache_init

此函数将对cpu的缓存进行初始化配置,这里暂时不去管它!

By: Keven - 点滴积累

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ongoingcre/article/details/50001333

智能推荐

java.lang.NoClassDefFoundError: javax/servlet/ServletContext_橙子cch的博客-程序员资料

@java.lang.NoClassDefFoundError: javax/servlet/ServletContextTOCjava.lang.NoClassDefFoundError: javax/servlet/ServletContext使用idea 开发项目,启动时报如下错误"D:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:D:\Program Files\IntelliJ IDEA Community Editi

史上最全的程序员求职渠道总结_yuwang668的博客-程序员资料

我前前后后写过多篇与程序员找工作相关的文章,比如程序员跳槽神级攻略,找工作的辟邪剑谱,任性,春节前辞职,程序员该不该考虑初创公司,这些文章都收录在我的漫谈程序员专栏里,它们从跳槽时机、跳槽原因、简历优化等不同侧面讨论了程序员找工作的那些事儿,受到很多人的关注。今天呢,我准备专门分析一下程序员求职渠道,有料是必须的,就算你搜遍互联网深挖全宇宙,也会发现这篇文章将是史上最全、最强、最有针对性的程序员求

java解析过程_【JVM系列】一步步解析java执行过程_令和时代的柯南的博客-程序员资料

对于任何一门语言,要想达到精通的水平,研究它的执行原理(或者叫底层机制)不失为一种良好的方式。在本篇文章中,将重点研究java源代码的执行原理,即从程序员编写JAVA源代码,到最终形成产品,在整个过程中,都经历了什么?每一步又是怎么执行的?执行原理又是什么?.....当然,本篇文章的粒度可能稍微侧重于宏观方面,更细粒度的技术分析,需要在接下来的该系列文章中与大家分享....一 编写java源程序j...

Android9.0无法加载http的url,net::ERR_CLEARTEXT_NOT_PERMITTED_一只小白程序员的博客-程序员资料

从Android 9.0(API级别28)开始,默认情况下禁用明文支持。因此http的url均无法在webview中加载附上我使用的解决办法:&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&amp;lt;manifest ...&amp;gt; &amp;lt;uses-permission android:name=&quot;android.permission...

使用HTML5+CSS+JS框架有那些好处_js+css的优势_qianduankuangjia的博客-程序员资料

相信很多程序猿朋友都用过框架,不过你是否知道你用的是HTML框架、CSS框架还是JS框架,其实这都不重要,重要的是使用框架的目的是什么?是不是节约了开发项目时间陈本,这事多么伟大的一箱工程,根据几年前的一片文章中写到,使用前端框架的优劣势,从这边文章中整理出一部分分享给大家。

docket常用命令_已运行docket run -d -t强行给容器进程发kill_amdiandds的博客-程序员资料

Docker是什么?开源软件部署方案,轻量级应用容器框架,可以打包发布任何,运行,任何应用。为什么要用Docket?

随便推点

初识前端框架Vue.js_初识vue.js在哪写_Chasel IBM的博客-程序员资料

Vue.js作为目前最热门最具前景的前端框架之一,其提供了一种帮助我们快速构建并开发前端项目的新的思维模式。本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程,并进一步理解如何通过Vue.js来构建一个中大型的前端项目,同时做好相应的部署与优化工作。文章将以PPT图片附加文字介绍的形式展开,不会涉及知识点的具体代码,点到为止。有兴趣的同学可以查看相应的文档进行了解。Vue.js简介从上图...

极速SpringCloud开发-Dalston版本_spring cloud dalston_白黑黑白的博客-程序员资料

服务的注册与发现(Eureka )在这里,我们需要用的的组件上Spring Cloud Netflix的Eureka ,eureka是一个服务注册和发现模块。Eureka介绍官方的介绍在这里Eureka wiki。Eureka是Netflix开源的一个RESTful服务,主要用于服务的注册发现。Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注...

深度学习Deep Learning 101_with the explosion of big data——a new product_GarfieldEr007的博客-程序员资料

Deep learning has become something of a buzzword in recent years with the explosion of 'big data', 'data science', and their derivatives mentioned in the media. Justifiably, deep learning approaches h

Nt vs. Zw - Clearing Confusion On The Native API _yebikangfu的博客-程序员资料

The NT native API is nothing new. It’s been discussed ad nauseum, it’s been exploited by umpteen different utilities, and portions of it have even migrated into the realm of the fully documented and s

【评测】一种组织蛋白快速提取方法_“泽平科技”公众号24h在线答疑的博客-程序员资料

以往认为脂肪组织是单纯能量储存器官,但随着脂肪组织在能量控制、炎症反应和免疫应答方面重要作用的验证,其已被确认也是一个内分泌器官。脂肪组织不仅响应来自传统内分泌系统和中枢神经系统的传入信号,还表达和分泌具有重要功能的细胞因子,包括瘦素(Leptin)、炎性细胞因子、脂联素(adiponectin)、补体成分、纤溶酶原激活物抑制剂-1(PAI-1)、肾素-血管紧张素系统蛋白和抵抗素(Resistin)等。脂肪组织中除了脂肪细胞外,还有干细胞、前脂肪细胞、巨噬细胞、嗜中性粒细胞、淋巴细胞和内皮细胞等。这些不

Spring Boot 动态定时任务---quartz(不需要重启服务)_quartz的任务 修改类用不用重新启动_qianhuan_的博客-程序员资料

一、配置文件quartz.properties#ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)org.quartz.scheduler.instanceId=AUTO#指定调度程序的主线程是否应该是守护线程org.quartz.scheduler.makeSchedulerThreadDaemon=true#ThreadPool实现的类名org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool#Thread

推荐文章

热门文章

相关标签