一. 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就会报错
-
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);
-
}
同时打印S3C_VIDINTCON0的值正好是0xf7100130,
也就是说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);
-
}
在arch/arm/mm/mmu.c中
-
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
阅读(1784) | 评论(0) | 转发(0) |