静态映射和动态映射

1、为什么需要映射

在内核启动过程中会开启MMU,建立虚拟映射表,以后内核使用的都是虚拟地址。但是我们查询数据手册得到I/O寄存器地址都是物理地址,于是需要将物理地址转换到虚拟地址,这样才能在内核空间去访问I/O寄存器。物理地址转换到虚拟地址就叫做映射,映射分为静态映射和动态映射。

2、动态映射和静态映射的比较

(1)建立映射的时机:静态映射是在内核启动过程中就建立好,并且在整个内核的生命周期都存在;动态映射是在需要的时候才进行,使用完后要解除映射;
(2)占用资源:静态映射是在内核启动就建立,所以会一直占用地址资源;动态映射只在映射的时候才占用地址资源,解除映射后就不再占用地址资源;
(3)访问速度:静态映射因为是一开始就映射好的,所以访问速度快;动态映射使用的时候要向申请再映射,所以访问速度稍慢一点;
(4)一般会把常访问的I/O地址设置成静态映射,因为访问速度更快;但是不能把太多物理地址设置成静态映射,因为静态映射会一直占用资源;

3、静态映射

3.1、struct machine_desc结构体

每个开发板都对应一个struct machine_desc结构体,因为嵌入式设备都是高度定制的,结构体里是针对该开发板的描述。其中成员变量map_io是个函数指针,每个开发板的静态映射就是该函数指针对应的函数完成的。struct machine_desc结构体的详细介绍见博客:《内核启动过程中机器码的确定》

3.2、静态映射的建立过程

	start_kernel
		setup_arch
			paging_init
				devicemaps_init
					if (mdesc->map_io)	// Ask the machine support to map in the statically mapped devices.s
						mdesc->map_io();

在devicemaps_init函数里去调用struct machine_desc结构体的map_io函数指针,也就是每个开发板特定的静态映射建立函数。从上面的代码还可以知道,静态映射不是必须的,在添加开发板对应的struct machine_desc结构体时,可以将map_io函数指针赋值为NULL,表示此开发板不需要静态映射。

3.3、struct map_desc结构体

	{
		unsigned long virtual;	 /* 映射后的虚拟地址 */
		unsigned long pfn;		 /* I/O资源物理地址所在的页帧号 */
		unsigned long length;	 /* I/O资源长度 */
		unsigned int type;		 /* I/O资源类型 */
	};

struct map_desc结构体是用来描述如何建立静态映射的,需要指明物理地址、映射后的虚拟地址、要映射的长度、映射的资源类型;其中物理地址传的是页帧号,因为内核建立的虚拟映射是以叶为单位的。

3.4、以X210开发板的map_io函数为例

#define S3C_ADDR_BASE	(0xFD000000)

#define S3C_ADDR(x)	(S3C_ADDR_BASE + (x))

#define S5P_VA_CHIPID		S3C_ADDR(0x00700000)
#define S5P_VA_GPIO			S3C_ADDR(0x00500000)

static struct map_desc s5p_iodesc[] __initdata = {
	{
		.virtual	= (unsigned long)S5P_VA_CHIPID,
		.pfn		= __phys_to_pfn(S5P_PA_CHIPID),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S3C_VA_SYS,
		.pfn		= __phys_to_pfn(S5P_PA_SYSCON),
		.length		= SZ_64K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S3C_VA_UART,
		.pfn		= __phys_to_pfn(S3C_PA_UART),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)VA_VIC0,
		.pfn		= __phys_to_pfn(S5P_PA_VIC0),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)VA_VIC1,
		.pfn		= __phys_to_pfn(S5P_PA_VIC1),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S3C_VA_TIMER,
		.pfn		= __phys_to_pfn(S5P_PA_TIMER),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S5P_VA_GPIO, //开发板的GPIO映射后的虚拟地址的基地址
		.pfn		= __phys_to_pfn(S5P_PA_GPIO), //开发板GPIO的物理地址基地址
		.length		= SZ_4K,	//要映射的长度					
		.type		= MT_DEVICE,	//资源类型
	},
};

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

	for (i = 0; i < nr; i++)
		create_mapping(io_desc + i);
}

void __init s5p_init_io(struct map_desc *mach_desc,
			int size, void __iomem *cpuid_addr)
{
	unsigned long idcode;

	/* initialize the io descriptors we need for initialization */
	iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc));
	if (mach_desc)
		iotable_init(mach_desc, size);

	idcode = __raw_readl(cpuid_addr);
	s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
}

static void __init smdkv210_map_io(void)
{
	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
	s3c24xx_init_clocks(24000000);
	s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs));
}

3.4.1、函数调用顺序:

	smdkv210_map_io
		s5p_init_io
			iotable_init
				create_mapping

3.4.2、函数调用说明

(1)X210开发板的map_io函数是smdkv210_map_io,这是在构建struct machine_desc结构体时指定的,见博客:《内核启动过程中机器码的确定》
(2)s5p_iodesc是struct map_desc类型的数组,每个struct map_desc类型的元素代表要进行静态映射的虚拟地址、物理地址已经映射的长度;
(3)create_mapping函数是真正构建静态映射的函数,将对s5p_iodesc数组里的每个元素进行解析,构建静态映射;

3.4.3、如何添加静态映射

 {
		.virtual	= (unsigned long)S5P_VA_GPIO, //开发板的GPIO映射后的虚拟地址的基地址
		.pfn		= __phys_to_pfn(S5P_PA_GPIO), //开发板GPIO的物理地址基地址
		.length		= SZ_4K,	//要映射的长度					
		.type		= MT_DEVICE,	//资源类型
	},

(1)在s5p_iodesc结构体数组中多添加一个struct map_desc 结构体成员,里面说明要映射的物理地址和虚拟地址;
(2)以s5p_iodesc结构体数组的最后一个成员为例,就是将物理地址S5P_PA_GPIO(0xE0200000)映射到虚拟地址S5P_VA_GPIO(0xFD500000)。物理地址就是从数据手册里查到的地址,映射后就可以在操作系统中用虚拟地址去访问那些物理地址。

4、动态映射

4.1、涉及的函数

//参数:物理地址、地址长度、名字
//返回值:成功、失败
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
//参数:要映射的物理地址、地址长度
//返回值:映射得到的虚拟地址
#define ioremap(cookie,size)           __ioremap(cookie,size,0) 
//参数:之前映射得到的虚拟地址
#define iounmap(cookie)			__iounmap(cookie)
//参数:之前申请的物理地址、地址长度
#define release_mem_region(start,n)	__release_region(&iomem_resource, (start), (n))

4.2、函数的调用次序

(1)request_mem_region:向内核申请物理地址资源;
(2)ioremap:将物理地址映射成虚拟地址;
(3)iounmap:解除物理地址到虚拟地址的映射;
(4)release_mem_region:通知内核释放物理地址;

4.3、示例代码

#define GPJ0CON_PA	0xe0200240
#define GPJ0DAT_PA 	0xe0200244

unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;

// 申请物理地址
if (!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))
	return -EINVAL;
if (!request_mem_region(GPJ0DAT_PA, 4, "GPJ0CON"))
	return -EINVAL;
	
//进行虚拟地址映射
pGPJ0CON = ioremap(GPJ0CON_PA, 4);
pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);

// 解除映射
iounmap(pGPJ0CON);
iounmap(pGPJ0DAT);
release_mem_region(GPJ0CON_PA, 4);
release_mem_region(GPJ0DAT_PA, 4);
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Spring Boot中,静态资源映射是由Spring Boot默认提供的配置完成的。Spring Boot将所有访问映射到以下目录:classpath:/static、classpath:/public、classpath:/resources和classpath:/META-INF/resources。如果这些目录中有多张同名的图片,访问地址的优先级顺序为:META-INF/resources > resources > static > public。\[2\] 如果我们请求一个以".html"结尾的静态资源,Spring Boot会按照优先级高的文件夹先查找,然后再查找优先级低的文件夹,直到找到指定的静态资源为止。\[3\] 例如,在src/main/resources/static目录下创建了一个hello.html文件,当我们启动Spring Boot并访问"http://localhost:8080/hello.html"时,就会显示该hello.html页面。\[3\] 总结来说,Spring Boot对静态资源映射提供了默认配置,可以直接将静态资源放置在指定的目录中,无需进行额外的配置即可访问这些静态资源。\[1\] #### 引用[.reference_title] - *1* *3* [Spring Boot静态资源映射](https://blog.csdn.net/weixin_64842782/article/details/125089662)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [springboot静态资源映射](https://blog.csdn.net/ChOLg/article/details/102800978)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值