移植linux到龙芯3210笔记3

    技术2022-05-19  52

    根据笔记2对Makefile的配置,接下来就应该加入这些平台相关的代码到相应的目录下。

    所以这次的主要任务是:增加代碼或修改代碼

     

    把平台相关的代碼,加入内核工程中:

    (1)将soc3210-board目录拷贝到arch/mips目录下,这里拷贝到arch/mips/mips-boards/

    这个目录将在arch/mips/kernel/Makefile中添加进去,这样集成到内核里。

    (2)将mach-longmeng目录拷贝到include/asm-mips/目录下,这部分代码也将在arch/mips/kernel/Makefile中添加进去,作为头文件路径。这部分代码是loongmeng平台的特殊性,对SOC32101不知道相不相关。

    (3)PCI操作相关的两个文件:fixup-soc-soc.c和ops-soc-soc.c拷贝到./arch/mips/pci/下。

    (4)把平台相关的头文件目录soc-soc/加入到./include/asm-mips/下面,其中soc_soc.h保存了外设资源的地址。

     

    在内核工程中的代碼上添加或修改平台相关的代碼:

    我们开始看代码,汇编部分不用作修改,直接看main.c文件,汇编head.S执行完之后直接跳转到main.c中的start_kernel函数。

    在start_kernel函数中,看与平台相关的函数setup_arch。

    (1)cpu_probe()   从函数名中看,这是一个探测CPU信息的函数,所以这肯定是一个需要修改的部分。

    进入cpu_probe,可以看到这个函数实际上就是读协处理器C0的PRId寄存器值。查看《See Mips Run》关于这部分的内容:

    31-----------------------24-23-------------------16-15-------------8-7----------------0

    |  Company Options   |     Company ID    |     CPU ID     |    Revision    |

    ------------------------------------------------------------------------------------------------

    Company ID字段是新近定义的,因此,以前的CPU都把其设为0。

    所以:

    struct cpuinfo_mips *c = ¤t_cpu_data; 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) { ... ... }  

    c->processor_id & 0xff0000为0 

    执行:cpu_probe_legacy(c);

    switch (c->processor_id & 0xff00) { ... ... }

    实际上开始判断CPU ID,然后根据CPU ID来填写cpuinfo_mips。

    在include/asm-mips/cpu.h中添加: 

    #definePRID_IMP_SOC32101 0x4200 #define CPU_SOC32101 65 #defineCPU_LAST 66

    在cpu_probe_legacy里增加PRID_IMP_SOC32101的操作:

    switch (c->processor_id & 0xff00) { case ... ... ... ... case PRID_IMP_SOC32101: c->cputype = CPU_SOC32101; c->isa_level = MIPS_CPU_ISA_II; c->options = R4K_OPTS | /* MIPS_CPU_FPU | */ MIPS_CPU_LLSC; c->tlbsize = 48; break; }

    对于上面定义的宏CPU_SOC32101,这个只是在本内核中的一个代号而已,没有特殊意义的。

    (2)在./arch/mips/kernel/proc.c中,在cpu_name数组下多加一个元素:

    static const char *cpu_name[] = { ... ... [CPU_SOC32101] = "SOC32101", }

    此时CPU_SOC32101就是刚才在cpu.h中定义的一个宏,而这个宏的具体值就是按这个数组的第几个元素,或者说是下标,则在本内核中所支持的CPU编号。当然了宏CPU_LAST的值就是最后的一个CPU编号,要大于或者等于最后一个,我们的最后一个是CPU_SOC32101。

    在show_cpuinfo()中可以看到打印这些信息的操作。相应地,在文件系统/proc下有一个cpuinfo的文件,cat cpuinfo就可以看到这些信息了。

    (3)关于mips_machgroup和mips_machtype这两个变量

     执行完cpu_probe之后就是prom_init()了。prom_init函数定义在./arch/mips/mips-boards/soc32101-boards/soc-soc/prom.c里面。这个文件是平台相关的,在笔记2里说的被拷贝到内核源码的平台相关代码。在prom_init函数一开始就对这两个变量进行赋值:

      mips_machgroup = MACH_GROUP_ICT; mips_machtype = MACH_SOC3210EV2E;

    所以MACH_GROUP_ICT和MACH_SOC3210EV2E这两个宏要定义了。

    关于组和类型的定义,一般在文件./include/asm-mips/bootinfo.h里定义的,所以在该文件里添加两个宏:

      #defineMACH_GROUP_ICT 23   #define MACH_SOC3210EV2E 5

    这两个宏的值不是特殊的值,只要不跟之前的重复了就行了。根据字面意思,大概这两个宏的意义是CPU组和该CPU在该组内的ID。这两个变量在代码中的具体的作用不太明确。因为之前已经存在一些CPU相关的宏定义了。当然用这两个变量也可以作一些与该CPU相关的特殊的操作。

    (4)在./include/asm-mips/modules.h里定义MODULE_PROC_FAMILY

    可以在看到这个文件里已经为各种支持的CPU都定义这个宏了,所以在后面加上:

     #elifdefined CONFIG_CPU_SOC32101  #defineMODULE_PROC_FAMILY "SOC32101"

    这个宏的实际意义不太清楚,搜索了一遍代码,没有发现代码中用到这个宏来作任何操作,但是如果不定义这个宏的话,编译会报错,因为:

    #else #error MODULE_PROC_FAMILY undefined for your processor configuration #endif

     (5)修改MM部分,主要是Cache和TLB

    编译通过之后,下载到开发板运行了一下,結果打印一些信息就停止了。后来跟踪代码发现进入trap_init之后,就不出来了。打开./arch/mips/kernel/traps.c查看trap_init函数,发现这个函数的主要功能是设置异常处理,不过在最后调用了两个函数:

    flush_icache_range(ebase, ebase + 0x400); flush_tlb_handlers(); 从函数的名字上可以看到这两个函数是操作cache和tlb的,程序就停在这里。 后查资料知道,龙芯CPU对Cache和TLB的管理有其特殊性,在笔记2的第4点也提到了。所以要对./arch/mips/mm/目录下的相关文件进行修改。

    在./include/asm-mips/cacheops.h中,

    修改:

    #define Hit_Invalidate_I 0x10

    为:

    #ifdefined(CONFIG_CPU_SOC32101) #defineHit_Invalidate_I 0x00 #else #defineHit_Invalidate_I 0x10 #endif

    如果编译报错找不到CONFIG_CPU_SOC32101这个宏,那么添加头文件#include <linux/config.h>。

     在./arch/mips/mm/c-r4k.c的函数probe_pcache里添加:

    switch (c->cputype) { case ... ... ...... break; caseCPU_SOC32101: icache_size= 1 << (12 + ((config & CONF_IC) >> 9)); c->icache.linesz= 16 << ((config & CONF_IB) >> 5); if(prid & 0x3) { c->icache.ways = 4; }else { c->icache.ways = 2; } c->icache.waybit=0; dcache_size= 1 << (12 + ((config & CONF_DC) >> 6)); c->dcache.linesz= 16 << ((config & CONF_DB) >> 4); if(prid & 0x3) { c->dcache.ways = 4; }else { c->dcache.ways = 2; } c->dcache.waybit= 0; break; }

     在./arch/mips/mm/tlb-r4k.c去掉宏定义BARRIER的意义:

    #ifdefined(CONFIG_CPU_SOC32101) #defineBARRIER #else …..... #endif

    在./arch/mips/mm/tlbex.c中加入操作码insn_dsrl32

    opcode枚举中加多一个成员:

    insn_dsrl32 

    insn_table加多一个成员:

    {insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE },

    build_get_pmde64函数中:

    修改:

    i_dsrl(p,tmp, tmp, PGDIR_SHIFT-3); 

    为:

    if(PGDIR_SHIFT - 3 >= 32) { i_dsrl32(p,tmp, tmp, PGDIR_SHIFT-3 - 32); /* get pgd offset in bytes */ }else{ i_dsrl(p,tmp, tmp, PGDIR_SHIFT-3); /* get pgd offset in bytes */ }

    这个函数从字面上看,是64位的操作,不太清楚这段的应用。

      在函数build_adjust_context中对shift变量操作加入:

    #ifdefCONFIG_PAGE_SIZE_16KB shift+=2; #endif

    这个是针对页面大小为16K的情况,页面大小可在内核配置里设置,一般都是4K

    按上面的记录修改后,内核跑过trap_init这个函数里,但是还是继续跑了一段就停止了,继续调试,找到原因。

     

    PS:这部分的修改非常重要,主要是根据实际的平台作相应的修改,特别是关于CPU的Cache和TLB部分,由于不太清楚,现在只是通过对比以前的内核来确定这些修改,而这些修改对移植到一个新的CPU是至关重要的,所以这部分要继续深入。

      

    --龙芯嵌入式系列开发板更多信息请关注  http://shop107479358.taobao.com 

    --龙芯1B开发板: http://item.taobao.com/item.htm?spm=a1z10.1.w4004-4678790104.8.WBYZuT&id=36562593290

     


    最新回复(0)