设备寄存器静态映射的建立

来源:互联网 发布: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++);
    }
}


struct map_desc {
    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 >> 20
crash> 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  


原创粉丝点击