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

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是至关重要的,所以这部分要继续深入。

  

-