Linux内核---46.关于mem_map

来源:互联网 发布:js attr style 编辑:程序博客网 时间:2024/06/06 00:50
一. Unable to handle kernel paging request at virtual address
移植LCD驱动,会出现如下的错误:
Unable to handle kernel paging request at virtual address 0xf7100130
定位一下发现是在drviers/video/samsun/s3cfb_fimd4x.c中,一调用writel就会报错
  1. void s3cfb_pre_init(void)
  2. {
  3.     s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
  4.     s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
  5.     s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
  6.     //打印dbmsg("S3C_VIDINTCON0=0x%x",S3C_VIDINTCON0);
  7.     writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  8. }
同时打印S3C_VIDINTCON0的值正好是0xf7100130,
也就是说0xf7100130这个虚拟地址没有与io端口相关联.
查找开发板自带的内核发现是在arch/arm/mach-s3c64xx/mach-smdk6410.c中,
添加了如下定义:
  1. static struct map_desc smdk6410_iodesc[] = {
  2.     {        
  3.         .virtual = (unsigned long)S3C_VA_LCD,   //0x
  4.         .pfn = __phys_to_pfn(S3C_PA_FB),
  5.         .length = SZ_16K,
  6.         .type = MT_DEVICE,
  7.     },
  8. };
那么这段代码有什么作用呢?
二. IO端口映射
用到smdk6410_iodesc的是:
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  1. static void __init smdk6410_map_io(void)
  2. {
  3.     //映射 IRQ SYS MEM TIMER WATCHDOG UART LCD
  4.     s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));   
  5. }

在arch/arm/mach-s3c64xx/cpu.c中
  1. void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
  2. {
  3.     unsigned long idcode;
  4.     //下面这一行映射 IRQ SYS MEM TIMER WATCHDOG UART 
  5.     iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));  
  6.     //下面这一行只映射LCD 
  7.     iotable_init(mach_desc, size);      //下面就以LCD为例说一下

  8.     idcode = __raw_readl(S3C_VA_SYS + 0x118);
  9.     if (!idcode) {
  10.         __raw_writel(0x0, S3C_VA_SYS + 0xA1C);
  11.         idcode = __raw_readl(S3C_VA_SYS + 0xA1C);
  12.     }

  13.     s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
  14. }

在arch/arm/mm/mmu.c中
  1. void __init iotable_init(struct map_desc *io_desc, int nr)
  2. {
  3.     //LCD的map_desc只有一项,所以这个nr=1
  4.     for (= 0; i < nr; i++)   
  5.         create_mapping(io_desc + i);
  6. }
在arch/arm/mm/mmu.c中
  1. static void __init create_mapping(struct map_desc *md)
  2. {
  3.     unsigned long addr, length, end;
  4.     phys_addr_t phys;
  5.     const struct mem_type *type;
  6.     pgd_t *pgd;

  7.     if (md->virtual != vectors_base() && md->virtual < TASK_SIZE)
  8.         return;    

  9.     if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
  10.      md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {        
  11.     }

  12.     type = &mem_types[md->type];
  13.     //页帧地址>0x100000,即实际的物理地址>0x100000000=4G, 大于4G的物理地址,现在不适合
  14.     if (md->pfn >= 0x100000) {    
  15.         create_36bit_mapping(md, type);
  16.         return;
  17.     }

  18.     addr = md->virtual & PAGE_MASK;
  19.     phys = __pfn_to_phys(md->pfn);
  20.     length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));

  21.     if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {       
  22.         return;
  23.     }

  24.     pgd = pgd_offset_k(addr);
  25.     end = addr + length;
  26.     do {
  27.         unsigned long next = pgd_addr_end(addr, end);
  28.         alloc_init_pud(pgd, addr, next, phys, type);
  29.         phys += next - addr;
  30.         addr = next;
  31.     } while (pgd++, addr != end);
  32. }

内存映射在内核启动时就会去映射,并且早于驱动的加载,如果没有映射端口就在驱动中使用了虚拟地址就会报上面的错误.

http://blog.chinaunix.net/uid-26009923-id-3860465.html
0 0