需要了解Embeded linux的地址映射

一、板级文件
通常会由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++);
}
}

肉制品检测仪器设备的产品概述说明
让我们看看物联网还剩下什么
联芯三大亮点闪耀MAE,推动3G/4G科技平民化
智能调度管理系统
政策助推,2017上半年中国AI投资总额达635亿元
需要了解Embeded linux的地址映射
PCI Express通过结合Nexus FPGA 技术平台与 LUT 实现以太网协议
中国联通正在携手华为打造基于5G网络建设的全场景综合解决方案
ACPL-M43U/M61U/M46U安华高工业应用
升级到iOS14后如何小窗口化
电桥测试仪能测试哪些东西_电桥测试仪可以测量磁通量吗?
软通动力ISSCloud ITSM一体化运维平台正式发布
PIE-3D Builder构建城市建筑群三维数字孪生底座
魅族pro7标准版跑分是多少?魅族pro7标准版打游戏怎么样?
UCloud优刻得与中国移动携手同行,共推5G+云网融合
R型特种变压器和常见变压器有什么不一样
ARM指令的寻址方式有几种?试分别举例说明
曝英特尔基频良率问题已解决,或将重获苹果3款iPhone的所有基频芯片订单
采用电容检测芯片PS021芯片实现微小电容测量电路的设计
Sub-1G胎压监测芯片可有效预防轮胎故障