设备寄存器静态映射的建立
来源:互联网 发布:c语言求质数用while 编辑:程序博客网 时间:2024/06/10 00:18
何时建立这个映射
/*
* Set up the device mappings. Since we clear out the page tables for all* mappings above VMALLOC_START, we will remove any debug device mappings.
* This means you have to be careful how you debug this function, or any
* called function. This means you can't use any function or debugging
* method which may touch any device, otherwise the kernel _will_ crash.
*/
static void __init devicemaps_init(struct machine_desc *mdesc)
{
/*
* Ask the machine support to map in the statically mapped devices.
*/
if (mdesc->map_io)
mdesc->map_io();
}
平台具体的函数
MACHINE_START(TL7689_PAD_TEST, "NUFRONT-TL7689-PAD-TEST").atag_offset = 0x100,
.map_io = tl7689_map_io,
.init_irq = pad_test_gic_init,
.timer = &tl7689_timer,
.handle_irq = gic_handle_irq,
.init_machine = tl7689_pad_test_init,
.init_early = tl7689_init_early,
MACHINE_END
void __init tl7689_map_io(void)
{
iotable_init(tl7689_io_desc, ARRAY_SIZE(tl7689_io_desc));
init_consistent_dma_size(SZ_16M - SZ_2M);
}
主题函数iotable_ini
/*
* Create the architecture specific mappings
*/
void __init iotable_init(struct map_desc *io_desc, int nr)
{
struct map_desc *md;
struct vm_struct *vm;
if (!nr)
return;
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++);
}
}
unsigned long virtual;
unsigned long pfn;
unsigned long length;
unsigned int type;
};
static void __init *early_alloc_aligned(unsigned long sz, unsigned long align)
{
void *ptr = __va(memblock_alloc(sz, align));
memset(ptr, 0, sz);
return ptr;
}
struct mem_type {
unsigned int prot_pte;
unsigned int prot_l1;
unsigned int prot_sect;
};
create_mapping
/*
* Create the page directory entries and any necessary* page tables for the mapping specified by `md'. We
* are able to cope here with varying sizes and address
* offsets, and we take full advantage of sections and
* supersections.
*/
static void __init create_mapping(struct map_desc *md, bool force_pages)
{
unsigned long addr, length, end;
phys_addr_t phys;
const struct mem_type *type;
pgd_t *pgd;
/*
*get the type,virtual/phy address, and length
**/
type = &mem_types[md->type];
addr = md->virtual & PAGE_MASK;
phys = __pfn_to_phys(md->pfn);
length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
pgd = pgd_offset_k(addr);
end = addr + length;
do {
/*得到下个PGDIR size*/
unsigned long next = pgd_addr_end(addr, end);
alloc_init_pud(pgd, addr, next, phys, type, force_pages);
phys += next - addr;
addr = next;
} while (pgd++, addr != end);
}
arch/arm/include/asm/pgtable.h
/* to find an entry in a kernel page-table-directory */#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
/* to find an entry in a page-table-directory */
#define pgd_index(addr) ((addr) >> PGDIR_SHIFT)
怎样判断是2/3 level?
#ifdef CONFIG_ARM_LPAE#include <asm/pgtable-3level.h>
#else
#include <asm/pgtable-2level.h>
#endif
crash> sys config | grep "CONFIG_ARM_LPAE"
# CONFIG_ARM_LPAE is not set
所以是 2 level
#define PGDIR_SHIFT 21
/*pgd = pgd_offset_k(addr);
*意思就是以init_mm的pgd为基地址,add右移21位作为Index,从而得到add对应的pgd
**/
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
unsigned long end, unsigned long phys, const struct mem_type *type,
bool force_pages)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
do {
next = pud_addr_end(addr, end);
alloc_init_section(pud, addr, next, phys, type, force_pages);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
include/asm-generic/pgtable-nopud.h
typedef struct {
pgd_t pgd;
} pud_t;
SIZE: 8
static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address)
{
return (pud_t *)pgd;
}
static void __init alloc_init_section(pud_t *pud, unsigned long addr,
unsigned long end, phys_addr_t phys,
const struct mem_type *type,
bool force_pages)
{
pmd_t *pmd = pmd_offset(pud, addr);
/*
* Try a section mapping - end, addr and phys must all be aligned
* to a section boundary. Note that PMDs refer to the individual
* L1 entries, whereas PGDs refer to a group of L1 entries making
* up one logical pointer to an L2 table.
*/
if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0 &&
!force_pages) {
pmd_t *p = pmd;
if (addr & SECTION_SIZE)
pmd++;
do {
*pmd = __pmd(phys | type->prot_sect);
phys += SECTION_SIZE;
} while (pmd++, addr += SECTION_SIZE, addr != end);
flush_pmd_entry(p);
}
}
static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
{
return (pmd_t *)pud;
}
crash> pmd_t
typedef unsigned int pmd_t;
SIZE: 4
终于向地址里写数了*pmd = __pmd(phys | type->prot_sect);
#define SECTION_SHIFT 20
#define SECTION_SIZE (1UL << SECTION_SHIFT)
section size 是 1 >> 20:1M .PDIR size为 1 >> 21: 2M,所以要写两次;
#define __pmd(x) ((pmd_t) { (x) } )
1-0:10 section
以已知的map_desc为例,看map的建立过程
map_desc:#define TL7689_PRCM_BASE 0x05821000 /* PRCM 4K */
{
.virtual = IO_ADDRESS(TL7689_PRCM_BASE),
.pfn = __phys_to_pfn(TL7689_PRCM_BASE),
.length = SZ_4K,
.type = MT_DEVICE,
},
arch/arm/mach-tl7689/include/mach/hardware.h
#define IO_ADDRESS(x) (((x) & 0x03ffffff) + 0xfb000000)crash> eval (0x05821000 & 0x03ffffff)
hexadecimal: 1821000 (24708KB)
crash> eval (0x01821000 + 0xfb000000)
hexadecimal: fc821000 (4137092KB)
crash> eval (fc821000 >> 21)
hexadecimal: 7e4
crash> eval (7e4*2)
hexadecimal: fc8
crash> eval (0xc0004000+0xfc8)
hexadecimal: c0004fc8
crash> rd c0004fc8
c0004fc8: 00000000 ....
怎么会是0啊?应该是0x05821000? 为什么?
已知虚拟地址fc821000
map_desc:
#define TL7689_PRCM_BASE 0x05821000 /* PRCM 4K */
{
.virtual = IO_ADDRESS(TL7689_PRCM_BASE),
.pfn = __phys_to_pfn(TL7689_PRCM_BASE),
.length = SZ_4K,
.type = MT_DEVICE,
},
arch/arm/mach-tl7689/include/mach/hardware.h
#define IO_ADDRESS(x) (((x) & 0x03ffffff) + 0xfb000000)
crash> eval (0x05821000 & 0x03ffffff)
hexadecimal: 1821000 (24708KB)
crash> eval (0x01821000 + 0xfb000000)
hexadecimal: fc821000 (4137092KB)
/*
* Convert a physical address to a Page Frame Number and back
*/
#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT))
#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT)
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
crash> eval (0x05821000 >> 12)
hexadecimal: 5821
展开后变为:
{
.virtual = 0xfc821000,
.pfn = 0x5821,
.length = SZ_4K,
.type = MT_DEVICE,
},
从打印的log看0xfc821000:对应的entry item address 是:0xc0007f20 = 0xc0004000 + 0x3f20
index是0x3f20,不是所说的 0xfc821000 >> 21 = 0x7e4:中间肯定有巧妙的转换
crash> rd 0xc0007f20
c0007f20: 40000000 ...@
以arm MMU的寻址方式得到虚拟地址对应的entry
crash> eval 0xfc821000 >> 20crash> eval (0xfc821000 >> 20)
hexadecimal: fc8
crash> eval (fc8 << 2)
hexadecimal: 3f20
wenshuai: trace mmu
wenshuai trace mmu: addr:0xfc821000, phys:0x5821000, length:0x1000
wenshuai trace mmu: pgd:0xc0007f20, end:0xfc822000
wenshuai trace mmu: pmd 0xc0007f20
wenshuai trace mmu: addr:0xfc822000, end:0xfc822000
还是没搞清楚,为什么两者不一致。
如果是以下的方式,两者会一直,哪里进行的处理啊
crash> eval (0xfc821000 >> 21)
hexadecimal: 7e4
crash> eval (7e4/2)
hexadecimal: 3f2
crash> eval (7e40/2)
hexadecimal: 3f20
- 设备寄存器静态映射的建立
- 静态映射表的建立过程
- 字符设备驱动高级篇5——静态映射表、动态映射结构体方式操作寄存器
- [译]映射设备寄存器到内存
- [译]映射设备寄存器到内存
- Linux驱动中建立动态映射来实现操作寄存器
- Linux内核访问外设I/O资源的方式(设备物理地址和设备虚拟地址),静态映射和动态映射
- Linux内核访问外设I/O资源的方式(设备物理地址和设备虚拟地址),静态映射和动态映射
- 【EDMA】DMA_TCDn_NBYTES寄存器的多种映射解析
- 寄存器名称和地址的映射分析
- 寄存器名称和地址的映射分析
- linux下特定处理器的设备物理地址和虚拟物理地址的静态映射的实现
- 建立Hibernate映射的新方法
- 虚拟地址的映射建立
- Linux内核静态映射表建立过程分析
- 设备节点的动态建立
- 设备节点的动态建立
- kernel-char设备的建立
- ORA-00119: invalid specification for system parameter LOCAL_LISTENER
- 在Spring3中,配置DataSource的方法有6种
- C 语言核心
- Weblogic :解决Managed Server启动非常慢的情况
- Latex等号对齐
- 设备寄存器静态映射的建立
- 获得指针(文档、视图、框架)
- Spring IOC
- 面试中可能用到的知识
- error:no type named iterator_category in struct
- 小KING教你做android项目(一)
- 位图(标量图)和矢量图的区别
- 如何防止用户重复提交表单
- 通向架构师的道路(第三天)之apache性能调优