当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]ARM Linux静态映射分析

在华清远见上课过程中,发现静态映射方面初学者比较难于掌握和理解,下面分析一下静态映射机制的原理并通过GPIO和USB、LCD等的静态映射作为例子来说明如何通过这种静态映射的方式访问外设资源。

内核提供了一个重要的结构体STruct machine_desc ,这个结构体在内核移植中起到相当重要的作用,内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。machine_desc结构体的成员包含了体系架构相关部分的几个最重要的初始化函数,包括map_io,init_IRq, init_machine以及phys_io , TImer成员等。

machine_desc结构体定义如下:

struct machine_desc {

/*

* Note! The first four elements are used

* by assembler code in head-armv.S

*/

unsigned int nr; /* architecture number */

unsigned int phys_io; /* start of physical io */

unsigned int io_pg_offst; /* byte offset for io

* page tabe entry */

cONst char *name; /* architecture nAME */

unsigned long ;boot_params; /* tagged list */

unsigned int video_start; /* start of video RAM */

unsigned int video_end; /* end of video RAM */

unsigned int reserve_lp0 :1; /* never has lp0 */

unsigned int reserve_lp1 :1; /* never has lp1 */

unsigned int reserve_lp2 :1; /* never has lp2 */

unsigned int soft_reboot :1; /* soft reboot */

void (*fixup)(struct machine_desc *,

struct tag *, char **,

struct meminfo *);

void (*map_io)(void);/* IO mapping function */

void (*init_irq)(void);

struct sys_timer *timer; /* system tick timer */

void (*init_machine)(void);

};

machine_desc结构体通过MACHINE_START宏来初始化,这里以s3c2410平台为例:

s3c2410 machine_desc结构体定义如下:

/* arch/arm/mach-s3c2410/mach-SMDk2410.c */

MACHINE_START(smdK2410, "SMDK2410") /* @TODO: request a new identifier and switch

* to SMDK2410 */

/* Maintainer: Jonas Dietsche */

.phys_io = S3C2410_PA_UART,

.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

.boot_params = S3C2410_SDRAM_PA + 0x100,

.map_io = smdk2410_map_io,

.init_irq = s3c24xx_init_irq,

.init_machine = smdk2410_init,

.timer = &s3c24xx_timer,

MACHINE_END

其中的宏MACHINE_START和MACHINE_END定义如下:

/*

* Set of macros to define architecture features. This is built into

* a table by the linker.

*/

#define MACHINE_START(_type,_name)

const struct machine_desc __mach_desc_##_type

__attribute__((__section__(".arch.info.init"))) = {

.nr = MACH_TYPE_##_type,

.name = _name,

#define MACHINE_END

};

其中MACH_TYPE_##_type 为GCC扩展语法中的字符拼接标识,在预编译的时候会用真正的字符代替,比如我们这里就是MACH_TYPE_SMDK2410

MACHINE_START的使用及各个成员函数的的放置位置以及调用过程如下:

MACH_TYPE_SMDK2410这个值是目标板的类型值,定义在arch/include/asm-arm/mach-types.h内,值为193.

/* arch/include/asm-arm/mach-types.h */

#define MACH_TYPE_SMDK2410 193

由上发现,MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,其所占用的内存在内核起来之后将会被释放。

这里的map_io成员即内核提供给用户的创建外设I/O资源到内核虚拟地址静态映射表的接口函数。map_io成员函数会在系统初始化过程中被调用,流程如下:

start_kernel -> setup_arch() --> paging_init()中被调用

struct machine_desc 结构体的各个成员函数在不同时期被调用:

1. .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall( ) 段里面,会自动按顺序被调用(另外博客分析,敬请关注)。

2. init_irq在start_kernel( ) --> init_IRQ( ) --> init_arch_irq( ) 被调用

3. map_io 在 setup_arch( ) --> paging_init( )被调用

其他主要都在 setup_arch() 中用到。

用户可以在定义machine_desc结构体时指定map_io的接口函数,我们也正是这样做的。

接下来我们继续分析smdk2410_map_io的执行过程,流程如下:

smdk2410_map_io-> s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc))

下面来看一下s3c24xx_init_io函数:

void __init s3c24xx_init_io(struct map_desc *mach_desc, int mach_size)

{

/* register our io-tables */

iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));

……

}

iotable_init内核提供,定义如下:

/*

* Create the architecture specific mappings

*/

void __init iotable_init(struct map_desc *io_desc, int nr)

{

int i;

for (i = 0; i nr; i++)

create_mapping(io_desc + i);

}

由上知道,smdk2410_map_io最终调用iotable_init建立映射表。

iotable_init函数的参数有两个:一个是map_desc类型的结构体,另一个是该结构体的数量nr。这里最关键的就是struct map_desc。map_desc结构体定义如下:

/* include/asm-arm/mach/map.h */

struct map_desc {

unsigned long virtual;

unsigned long physical;

unsigned long length;

unsigned int type;

};

create_mapping( )函数就是通过map_desc提供的信息创建线性映射表的。

这样的话我们就知道了创建I/O映射表的大致流程为:只要定义相应I/O资源的map_desc结构体,并将该结构体传给iotable_init函数执行,就可以创建相应的I/O资源到内核虚拟地址空间的映射表了。

我们来看看s3c2410是怎么定义map_desc结构体的(即上面iotable_init()函数内的s3c_iodesc)。

[arch/arm/mach-s3c2410/CPU.c]

/* minimal IO mapping */

static struct map_desc s3c_iodesc[] __initdata = {

IODESC_ENT(GPIO),

IODESC_ENT(IRQ),

IODESC_ENT(MEMCTRL),

IODESC_ENT(UART)

};

IODESC_ENT宏如下:

#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE }

展开后等价于:

static struct map_desc s3c_iodesc[] __initdata = {

{

.virtual = S3C24XX_VA_GPIO,

.physical = S3C24XX_PA_GPIO,

.length = S3C24XX_SZ_GPIO,

.type = MT_DEVICE

},

……

};

至此,我们可以比较清晰看到GPIO被静态映射的过程,由于我们在前面的静态映射中已经做好了GPIO的映射,也就是我们写GPIO相关驱动的时候可以如下配置引脚的原因:

s3c2410_gpio_cfgpin(xxx,xxx);

其实,s3c2410_gpio_cfgpin定义如下:

void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

{

void __iomem *base = S3C2410_GPIO_BASE(pin);

unsigned long mask;

unsigned long con;

unsigned long flags;

if (pin < S3C2410_GPIO_BANKB) {

mask = 1 << S3C2410_GPIO_OFFSET(pin);

} else {

mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;

}

local_irq_save(flags);

con = __raw_readl(base + 0x00);

con &= ~mask;

con |= function;

__raw_writel(con, base + 0x00);

local_irq_restore(flags);

}

其中,比较关键的一个地方:

void __iomem *base = S3C2410_GPIO_BASE(pin);

这一行中,S3C2410_GPIO_BASE定义如下:

#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

至此,GPIO的静态映射就看得很明白了。

下面来看其他外设的静态映射:

在s3c24xx_init_io()函数中,除了iotable_init()以为,还会在最后调用,

(CPU->map_io)(mach_desc, size);

而CPU的这个map_io在arch/arm/mach-s3c2410/cpu.c里面定义如下:

static struct cpu_table cpu_ids[] __initdata = {

{

.idcode = 0x32410000,

.idmask = 0xffffffff,

.map_io = s3c2410_map_io,

.init_clocks = s3c2410_init_clocks,

.init_uarts = s3c2410_init_uarts,

.init = s3c2410_init,

.name = name_s3c2410

},

...

}

再查看s3c2410_map_io(),函数代码如下:

void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)

{

/* register our io-tables */

iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));

iotable_init(mach_desc, mach_size);

}

接下来看结构s3c2410_iodesc [arch/arm/mach-s3c2410/s3c2410.c],代码如下,

/* Initial IO mappings */

static struct map_desc s3c2410_iodesc[] __initdata = {

IODESC_ENT(USBHOST),

IODESC_ENT(USBDEV),

IODESC_ENT(CLKPWR),

IODESC_ENT(LCD),

IODESC_ENT(TIMER),

IODESC_ENT(ADC),

IODESC_ENT(WATCHDOG),

};

赫然发现IODESC_ENT(TIMER)这一行,结合之前GPIO的类似分析,IODESC_ENT宏如下:

#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE }

至此,TIMER, USBHOST,USBDEV,lcd,adc,watchdog等的静态映射都看得很明白了。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭