移植linux到龙芯3210笔记3

来源:互联网 发布:2006年nba总决赛数据 编辑:程序博客网 时间:2024/06/05 22:54

根据笔记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