linux io映射,【原创】Linux 文件系统移植全解密以linux-2.6.35内核源码为例说明一下IO静态映射的过程...
最近不斷有人跟我說起靜態映射的問題,今天就以linux-2.6.35內核源碼為例說明一下IO靜態映射的過程(ARM平臺)。
//init/main.c
asmlinkage void __init start_kernel(void){
...
setup_arch(&command_line);
...
}
//arch/arm/kernel/setup.c
void __init setup_arch(char **cmdline_p){
...
paging_init(mdesc);
...
}
//arch/arm/mm/mmu.c
void __init paging_init(struct machine_desc *mdesc){
...
devicemaps_init(mdesc);
...
}
//arch/arm/mm/mmu.c
static void __init devicemaps_init(struct machine_desc *mdesc){
...
if (mdesc->map_io) ?//回調map_io
mdesc->map_io();
...
}
//arch/arm/include/asm/mach/arch.h
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head.S, head-common.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);
};
該結構體對象初始化在對應板子的BSP文件中(這里以S5PC100平臺為例)
//arch/arm/mach-s5pc100/mach-smdkc100.c
MACHINE_START(SMDKC100, "SMDKC100")
/* Maintainer: Byungho Min */
.phys_io ? ?= S3C_PA_UART & 0xfff00000,
.io_pg_offst ? ?= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
.boot_params ? ?= S5P_PA_SDRAM + 0x100,
.init_irq ? ?= s5pc100_init_irq,
.map_io ? ? ? ?= smdkc100_map_io,
.init_machine ? ?= smdkc100_machine_init,
.timer ? ? ? ?= &s3c24xx_timer,
MACHINE_END
//MACHINE_START宏定義在arch/arm/include/asm/mach/arch.h
#define MACHINE_START(_type,_name) ? ? ? ? ? ?\
static const struct machine_desc __mach_desc_##_type ? ?\
__used ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
__attribute__((__section__(".arch.info.init"))) = { ? ?\
.nr ? ? ? ?= MACH_TYPE_##_type, ? ? ? ?\
.name ? ? ? ?= _name,
#define MACHINE_END ? ? ? ? ? ? ? ?\
即struct machine_desc中的域.map_io登記為smdkc100_map_io
static void __init smdkc100_map_io(void)
{
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
...
}
//arch/arm/plat-s5p/cpu.c
/* minimal IO mapping */
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,
.pfn ? ? ? ?= __phys_to_pfn(S5P_PA_GPIO),
.length ? ? ? ?= SZ_4K,
.type ? ? ? ?= MT_DEVICE,
},
};
/* read cpu identification code */
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));
}
上面的 iotable_init函數完成IO映射。
結構體static struct map_desc定義在asm/io.h中
struct map_desc {
unsigned long virtual; //映射后的虛擬地址
unsigned long pfn; ? ? ?//被映射的物理地址所在頁幀號
unsigned long length;//被映射的IO資源長度
unsigned int type; ? ? ? ?//IO類型
};
這里比較難理解的是“映射后的虛擬地址virtual”,這個是自己定義的,可以修改,但是不能和已經映射的重復。
可以參看內核文檔\Documentation\arm\memory.txt,其中描述如下:
VMALLOC_START ? ?VMALLOC_END-1 ? ?vmalloc() / ioremap() space.
Memory returned by vmalloc/ioremap will
be dynamically placed in this region.
VMALLOC_START may be based upon the value
of the high_memory variable.
VMALLOC_START 定義在arch/arm/include/asm/pgtable.h中
/*
* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. ?That means that
* any out-of-bounds memory accesses will hopefully be caught.
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*
* Note that platforms may override VMALLOC_START, but they must provide
* VMALLOC_END. ?VMALLOC_END defines the (exclusive) limit of this space,
* which may not overlap IO space.
*/
#ifndef VMALLOC_START
#define VMALLOC_OFFSET ? ? ? ?(8*1024*1024)
#define VMALLOC_START ? ? ? ?(((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#endif
S5PC100中IO映射從S3C_ADDR_BASE開始線性偏移
#define S3C_ADDR_BASE ? ?(0xF4000000)
總結
以上是生活随笔為你收集整理的linux io映射,【原创】Linux 文件系统移植全解密以linux-2.6.35内核源码为例说明一下IO静态映射的过程...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机和Linux蓝牙通信,[原创]lin
- 下一篇: 怎么复制远程服务器上的文件夹,Linux