一、板级文件
一般会由MACHINE_START到板级文件
MACHINE_START(Chipname, “Chipname”)
.atag_offset = 0x100,
.map_io = Chipname_map_io,
.init_early = Chipname_init_early,
.init_irq = Chipname_gic_init_irq,
.handle_irq = gic_handle_irq,
.timer = &Chipname_sys_TImer,
.init_machine = Chipname_init,
.reserve = Chipname_reserve,
.restart = Chipname_restart,
MACHINE_END
.map_io是一个函数指针,这儿指定了Chipname_map_io。函数实体为:
void __init Chipname_map_io(void)
{
…
}
二、内存映射
芯片IO口操作分为两类:
1.寄存器与内存一致编址,又称IO内存
2.寄存器与内存不一致编址,又称IO端口
ARM芯片基本上是一致编址,拜访寄存器(包含体系寄存器、外设寄存器、IO口寄存器等)直接拜访该地址即可。
其间linux支撑的寄存器地址寻址方法为内存映射,行将内核内存1G的某一些地址映射给寄存器,这样操作内核虚拟内存地址便是操作寄存器。
三、映射方法
linux内核供给的映射方法有两种:
1.静态映射
运用map_desc结构体进行映射,其间map_desc结构体为:
struct map_desc {
unsigned long virtual; //虚拟地址
unsigned long pfn; //__phys_to_pfn(物理地址) , 便是物理页框号
unsigned long length; //长度
unsigned int type; //类型
};
举例,填充一个映射信息结构体,映射两块接连的地址空间,呈现保留字就再映射一个,或许遇到不需要操控的地址,不然一向接连映射:
staTIc struct map_desc Chipname_io_desc[] __initdata = {
{
.virtual = 0xFE000000,
.pfn = __phys_to_pfn(0x10000000),
.length = 0xD0000,
.type = MT_DEVICE
},
{
.virtual = 0xFE100000,
.pfn = __phys_to_pfn(0x20000000),
.length = 0x700000,
.type = MT_DEVICE
}
};
然后调用iotable_init(Chipname_io_desc, ARRAY_SIZE(Chipname_io_desc));树立映射的函数
今后直接*(volaTIle unsigned int *)0xFE000000就能运用了。
2.动态映射
驱动中手动映射某一个地址
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cached(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap __arm_iounmap
cookie:物理地址
size:要映射的空间的巨细;
回来虚拟地址
头文件io.h
今后直接*(volaTIle unsigned int *)虚拟地址就能运用了。
扩展:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) //include/linux/kernel.h,ARRAY_SIZE为核算数组的一维维度,核算方法为数组巨细和数组单成员巨细之商
#ifdef __CHECKER__
#define __must_be_array(arr) 0
#else
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) //include/linux/compiler-gcc.h
#endif
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) //include/linux/bug.h,BUILD_BUG_ON_ZERO的效果在于将回来值转化为编译错误信息。明显当内嵌函数回来值为0时,也即类型相一起,因为BUILD_BUG_ON_ZERO参数为非0而导致char[-1]而宣布编译器正告。
#ifndef __same_type
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) //include/linux/compiler.h,gcc编译器内嵌的函数,判别一个变量的类型是否为某指定的类型,假如是就回来1,不然回来0。这儿经过判别指针和指针指向的第一个元素的指针是否是相同类型来判别是否为数组。
#endif
arch/arm/mm/mmu.c
void __init iotable_init(struct map_desc *io_desc, int nr)
{
struct map_desc *md;
struct vm_struct *vm;
if (!nr) return;
/*early_alloc_aligned
*
*/
vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
for (md = io_desc; nr; md++, nr–)
{
create_mapping(md, false);
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(md->type);
vm->caller = iotable_init;
vm_area_add_early(vm++);
}
}