一. 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就会报错
同时打印S3C_VIDINTCON0的值正好是0xf7100130,
也就是说0xf7100130这个虚拟地址没有与io端口相关联.
查找开发板自带的内核发现是在arch/arm/mach-s3c64xx/mach-smdk6410.c中,
添加了如下定义:
那么这段代码有什么作用呢?
二. IO端口映射
用到smdk6410_iodesc的是:
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
在arch/arm/mach-s3c64xx/cpu.c中
在arch/arm/mm/mmu.c中
在arch/arm/mm/mmu.c中
内存映射在内核启动时就会去映射,并且早于驱动的加载,如果没有映射端口就在驱动中使用了虚拟地址就会报上面的错误.
http://blog.chinaunix.net/uid-26009923-id-3860465.html
移植LCD驱动,会出现如下的错误:
Unable to handle kernel paging request at virtual address 0xf7100130
定位一下发现是在drviers/video/samsun/s3cfb_fimd4x.c中,一调用writel就会报错
- void s3cfb_pre_init(void)
- {
- s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
- s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
- s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
- //打印dbmsg("S3C_VIDINTCON0=0x%x",S3C_VIDINTCON0);
- writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
- }
也就是说0xf7100130这个虚拟地址没有与io端口相关联.
查找开发板自带的内核发现是在arch/arm/mach-s3c64xx/mach-smdk6410.c中,
添加了如下定义:
- static struct map_desc smdk6410_iodesc[] = {
- {
- .virtual = (unsigned long)S3C_VA_LCD, //0x
- .pfn = __phys_to_pfn(S3C_PA_FB),
- .length = SZ_16K,
- .type = MT_DEVICE,
- },
- };
二. IO端口映射
用到smdk6410_iodesc的是:
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
- static void __init smdk6410_map_io(void)
- {
- //映射 IRQ SYS MEM TIMER WATCHDOG UART LCD
- s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
- }
在arch/arm/mach-s3c64xx/cpu.c中
- void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
- {
- unsigned long idcode;
- //下面这一行映射 IRQ SYS MEM TIMER WATCHDOG UART
- iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
- //下面这一行只映射LCD
- iotable_init(mach_desc, size); //下面就以LCD为例说一下
-
- idcode = __raw_readl(S3C_VA_SYS + 0x118);
- if (!idcode) {
- __raw_writel(0x0, S3C_VA_SYS + 0xA1C);
- idcode = __raw_readl(S3C_VA_SYS + 0xA1C);
- }
-
- s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
- }
在arch/arm/mm/mmu.c中
- void __init iotable_init(struct map_desc *io_desc, int nr)
- {
- //LCD的map_desc只有一项,所以这个nr=1
- for (i = 0; i < nr; i++)
- create_mapping(io_desc + i);
- }
- static void __init create_mapping(struct map_desc *md)
- {
- unsigned long addr, length, end;
- phys_addr_t phys;
- const struct mem_type *type;
- pgd_t *pgd;
-
- if (md->virtual != vectors_base() && md->virtual < TASK_SIZE)
- return;
-
- if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
- md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
- }
-
- type = &mem_types[md->type];
- //页帧地址>0x100000,即实际的物理地址>0x100000000=4G, 大于4G的物理地址,现在不适合
- if (md->pfn >= 0x100000) {
- create_36bit_mapping(md, type);
- return;
- }
-
- addr = md->virtual & PAGE_MASK;
- phys = __pfn_to_phys(md->pfn);
- length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-
- if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
- return;
- }
-
- pgd = pgd_offset_k(addr);
- end = addr + length;
- do {
- unsigned long next = pgd_addr_end(addr, end);
- alloc_init_pud(pgd, addr, next, phys, type);
- phys += next - addr;
- addr = next;
- } while (pgd++, addr != end);
- }
内存映射在内核启动时就会去映射,并且早于驱动的加载,如果没有映射端口就在驱动中使用了虚拟地址就会报上面的错误.
http://blog.chinaunix.net/uid-26009923-id-3860465.html