3.5.1.92. FD_ALIGN

#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))

FDT_ALIGN 用于将x参数按照a对齐

3.5.1.93. fdt_boot_cpuid_phys

#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))

fdt_boot_cpuid_phys 用于读取DTB header的boot_cpuid_phys信息

3.5.1.94. fdt_check_header

int fdt_check_header(const void *fdt)
{
    size_t hdrsize;

    //检查dtb的magic是否有效
    if(fdt_magic(fdt) != FDT_MAGIC)
        return -FDT_ERR_BADMAGIC;

    //获取dtb header大小
    hdrsize = fdt_header_size(fdt);
    //判断dtb版本
    if((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) ||
        (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
            return -FDT_ERR_BADVERSION;

    if(fdt_version(fdt) < fdt_last_comp_version(fdt))
        return -FDT_ERR_BADVERSION;
    //如果dtb长度比dtb header小,或者dtb 长度比INT_MAX大,则认为dtb无效
    if((fdt_totalsize(fdt) < hdrsize) || (fdt_totalsize(fdt) > INT_MAX))
        return -FDT_ERR_TRUNCATED;

    //检查dtb reserved区域是否在大于dtb header而小于dtb 二进制大小的区域内
    if(!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
        return -FDT_ERR_TRUNCTED;

    //如果dtb版本小于17,如果此时devicetree struct的位置不再hdrsize和totalsize之间,则认定dtb无效
    if(fdt_version(fdt) < 17) {
        if(!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_dt_struct(fdt)))
            return -FDT_ERR_TRUNCTED;
    } else {
        if(!check_block_(hdrsize, fdt_totalsize(fdt), fdt_off_dt_struct(fdt), fdt_size_dt_struct(fdt)))
            return -FDT_ERR_TRUNCTED;
    }

    if(!check_block_(hdrsize, fdt_totalsize(fdt), fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
        return -FDT_ERR_TRUNCTED;

    return 0;
}

fdt_check_header 用于检查DTB二进制文件是否有效

3.5.1.95. fdt_check_node_offset

int fdt_check_node_offset_(const void *fdt, int offset)
{
    if((offset <  0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
        return -FDT_ERR_BADOFFSET;

    return offset;
}

fdt_check_node_offset_ 用于判断offset对应的值是否为fdt device node

3.5.1.96. fdt_check_prop_offset

//fdt: 指向dtb
//offset: property在dtb devicetree structure内偏移
int fdt_check_prop_offset_(const void *fdt, int offset)
{
    if((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
        return -FDT_ERR_BADOFFSET;

    return offset;
}

fdt_check_prop_offset_ 用于判断offset对应的tag是否为fdt property.

3.5.1.97. fdt_first_property_offset

int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
    int offset;

    if((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
        return offset;

    return nextprop_(fdt, offset);
}

fdt_first_property_offset 用于获得device node的第一个属性在dtb devicetree structure区域内的偏移

3.5.1.98. fdt_get_property_by_offset

static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, int offset, int *lenp)
{
    int err;
    const struct fdt_property *prop;

    if((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
        if(lenp)
            *lenp = err;
        return NULL;
    }

    prop = fdt_offset_ptr_(fdt, offset);

    if(lenp)
        *lenp = fdt32_ld(&prop->len);

    return prop;
}

fdt_get_property_by_offset_ 通过属性在dtb devicetree structure区域内的偏移获取属性值的长度.

3.5.1.99. fdt_header_size_

#define FDT_V1_SIZE         (7*sizeof(fdt32_t))
#define FDT_V2_SIZE         (FDT_V1_SIZE + sizeof(fdt32_t))
#define FDT_V3_SIZE         (FDT_V2_SIZE + sizoef(fdt32_t))
#define FDT_V16_SIZE        FDT_V3_SIZE
#define FDT_V17_SIZE        (FDT_V16_SIZE + sizeof(fdt32_t))

size_t fdt_header_size_(uint32_t version)
{
    if(version <= 1)
        return FDT_V1_SIZE;
    else if(version <= 2)
        return FDT_V2_SIZE;
    else if(version <= 3)
        return FDT_V3_SIZE;
    else if(version <= 16)
        return FDT_V16_SIZE;
    else
        return FDT_V17_SIZE;
}

fdt_header_size_ 用于获得dtb header结构的长度

3.5.1.100. fdt_header_size

static inline size_t fdt_header_size(const void *fdt)
{
    return fdt_header_size_(fdt_version(fdt));
}

3.5.1.101. fdt_init_reserved_mem

void __init fdt_init_reserved_mem(void)
{
    int i;

    //检查reserved_mem数组对应的预留区是否存在重叠部分
    __rmem_check_for_overlap();

    for(i = 0; i < reserved_mem_count; i++) {
        struct reserved_mem *rmem = &reserved_mem[i];
        unsigned long node = rmem->fdt_node;
        int len;
        const __be32 *prop;
        int err = 0;

        //获得节点的phandle或linux,phandle属性
        prop = of_get_flat_dt_prop(node, "phandle", &len);
        if(!prop)
            prop = of_get_flat_dt_prop(node, "linux,phandle", &len);
        if(prop)
            rmem->phanlde = of_read_number(prop, len/4);

        //为预留区分配内存
        if(rmem->size == 0)
            err = __reserved_mem_alloc_size(node, rmem->name, &rmem->base, &rmem->size);

        //初始化预留区
        if(err == 0)
            __reserved_mem_init_node(rmem);
    }
}

fdt_init_reserved_mem 用于为reserved_mem[]数组内的保留区分配内存并初始化预留区

3.5.1.102. fdt_get_header

#define fdt_get_header(fdt, field)  \
    (fdt32_ld(&((const struct fdt_header *)(fdt))->field))

fdt_get_header 用于从dtb的header读取指定的信息.

3.5.1.103. fdt_get_mem_rsv

int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
    const struct fdt_reserve_entry *re;

    FDT_RO_PROBE(fdt);
    re = fdt_mem_rsv(fdt, n);
    if(!re)
        return -FDT_ERR_BADOFFSET;

    *address = fdt64_ld(&re->address);
    *size = fdt64_ld(&re->size);

    return 0;
}

fdt_get_mem_rsv 用于获得dtb保留区中指定区域的地址和长度

3.5.1.104. fdt_get_name

//fdt: 指向dtb
//nodeoffset: device-node在dtb devicetree structure区域内的偏移
//len: 用于存储名字的长度
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
    //获取nodeoffset对应的指针
    const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
    const char *nameptr;
    int err;

    //对fdt进行最小健全性检测,以及检查device-node的合法性
    if((err = fdt_ro_probe_(fdt)) != 0 || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
        goto fail;

    //获取name
    nameptr = nh->name;

    //如果当前版本小于17
    if(fdt_version(fdt) < 0x10) {
        const char *leaf;
        leaf = strrchr(nameptr, '/');
        if(leaf == NULL) {
            err = -FDT_ERR_BADSTRUCTURE;
            goto fail;
        }
        nameptr = leaf + 1;
    }

    if(len)
        *len = strlen(strlen(nameptr));

    return nameptr;

fail:
    if(len)
        *len = err;
    return NULL;
}

fdt_get_name 通过节点的偏移获得节点的名字.

3.5.1.105. fdt_get_property_namelen

//fdt: 指向dtb
//offset: property在dtb devicetree structure中的偏移
//name: 需要查找的property名字
//namelen: 名字的长度
//lenp: 用于存储property的偏移
static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, int offset, const char *name,
                                                        int namelen, int *lenp, int *poffset)
{
    //获得offset参数开始之后的第一个property
    for(offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) {
        const struct fdt_property *prop;

        if(!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
            offset = -FDT_ERR_INTERNAL;
            break;
        }

        //对比property属性名字是否和name参数一致
        if(fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), name, namelen)) {
            if(poffset)
                *poffset = offset;
            return prop;
        }
    }
    if(lenp)
        *lenp = offset;

    return NULL;
}

fdt_get_property_namelen_ 通过name参数获得dtb中的property

3.5.1.106. fdt_get_string

const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
    //计算字符串在dtb内的偏移
    uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
    size_t len;
    int err;
    const char *s, *n;

    //对dtb进行最小健全性检查
    err = fdt_ro_probe_(fdt);
    if(err != 0)
        goto fail;

    err = -FDT_ERR_BADOFFSET;
    //判断offset是否超过fdt的size
    If(absoffset >= fdt_totalsize(fdt))
        goto fail;
    len = fdt_totalsize(fdt) - absoffset;

    //获取dtb的magic并做不同的处理
    if(fdt_magic(fdt) == FDT_MAGIC) {
        if(stroffset < 0)
            goto fail;

        if(fdt_version(fdt) >= 17) {
            if(stroffset >= fdt_size_dt_strings(fdt))
                goto fail;
            if((fdt_size_dt_strings(fdt) - stroffset) < len)
                len = fdt_size_dt_strings(fdt) - stroffset;
        }
    } else if(fdt_magic(fdt) == FDT_SW_MAGIC) {
        if((stroffset >= 0) || (stroffset < -fdt_size_dt_strings(fdt)))
            goto fail;
        if((-stroffset) < len)
            len = -stroffset;
    } else {
        err = -FDT_ERR_INTERNAL;
        goto fail;
    }

    s = (const char *)fdt + absoffset;
    n = memchr(s, '\', len);

    if(!n) {
        err = -FDT_ERR_TRUNCATED;
        goto fail;
    }

    if(lenp)
        *lenp = n - s;

    return s;
}

fdt_get_string 通过字符串在dtb devicetree strings区域内的偏移,获得对应的字符串

3.5.1.107. fdt_getprop

const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name ,int *lenp)
{
    return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}

fdt_getprop 通过名字获得device-node中的属性值

3.5.1.108. fdt_getprop_namelen

const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp)
{
    int poffset;
    const struct fdt_property *prop;

    prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, &poffset);
    if(!prop)
        return NULL;

    if(fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
        return prop->data + 4;

    return prop->data;
}

fdt_getprop_namelen 用于获得device-node内部属性的值

3.5.1.109. fdt_last_comp_version

#define fdt_last_comp_version(fdt)      (fdt_get_header(fdt, last_comp_version))

fdt_last_comp_version 用于读取dtb header的last_comp_version信息

3.5.1.110. fdt_magic

#define fdt_magic(fdt) (fdt_get_header(fdt, magic))

3.5.1.111. fdt_mem_rsv

int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
    const struct fdt_reserve_entry *re;

    FDT_RO_PROBE(fdt);
    re = fdt_mem_rsv(fdt, n);
    if(!re)
        return -FDT_ERR_BADOFFSET;

    *address = fdt64_ld(&re->address);
    *size = fdt64_ld(&re->size);

    return 0;
}

fdt_get_mem_rsv 用于获取dtb保留区中指定区域的地址和长度

3.5.1.112. fdt_next_node

//fdt: 指向dtb
//offset: 指向当前device-node在dtb devicetree structure区域中的偏移
//depth: 用于识别当前节点的深度
int fdt_next_node(const void *fdt, int offset, int *depth)
{
    int nexoffset = 0;
    uint32_t tag;

    //判断offset对应的device-node是否有效
    if(offset >= 0)
        if((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)

    do {
        offset = nextoffset;
        //获取当前tag的下一个tag及偏移
        tag = fdt_next_tag(fdt, offset, &nextoffset);

        switch(tag) {
        case FDT_PROP:
        case FDT_NOP:
            break;
        //如果tag值为FDT_BEGIN_NODE,那么当前节点包含了一个子节点
        case FDT_BEGIN_NODE:
            if(depth)
                (*depth)++;
            break;
        case FDT_END_NODE:
            if(depth && ((--(*depth)) < 0))
                return nextoffset;
            break;
        case FDT_END:
            if((nextoffset >= 0) || ((nextoffset == -FDT_ERR_TRUNCTED) && !depth))
                return -FDT_ERR_NOTFOUND;
            else
                return nextoffset;
        }
    } while(tag != FDT_BEGIN_NODE);

    return offset;
}

fdt_next_node 用于获得当前device-node的下一个device-node

3.5.1.113. fdt_next_tag

uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
    const fdt32_t *tagp, *lenp;
    uint32_t tag;
    int offset = startoffset;
    const char *p;

    *nextoffset = -FDT_ERR_TRUNCATED;
    tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
    if(!tagp)
        return FDT_END;
    tag = fdt32_to_cpu(*tagp);
    offset += FDT_TAGSIZE;

    *nextoffset = -FDT_ERR_BADSTRUCTURE;
    switch(tag) {
    case FDT_BEGIN_NODE:
        do {
            p = fdt_offset_ptr(fdt, offset++, 1);
        } while(p && (*p != '\0'));
        if(!p)
            return FDT_END;
        break;

    case FDT_PROP:
        lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
        if(!lenp)
            return FDT_END;
        offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp);
        if(fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
            offset += 4;
        break;
    case FDT_END:
    case FDT_END_NODE:
    case FDT_NOP:
        break;
    }

}

3.5.1.114. fdt_off_dt_strings

#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))

fdt_off_dt_strings 用于读取dtb header的off_dt_strings信息.

3.5.1.115. fdt_offset_ptr

//fdt: 指向dtb
//offset: device-node在dtb structure区域内的偏移
//len: 表示device-node的长度
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
    unsigned absoffset = offsdt + fdt_off_dt_struct(fdt);

    if((absoffset < offset) || ((absoffset + len) < absoffset)
    || (absoffset + len) > fdt_totalsize(fdt))
        return NULL;

    if(fdt_version(fdt) >= 0x11)
        if(((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt)))
            return NULL;

    return fdt_offset_ptr_(fdt, offset);
}

fdt_offset_ptr 通过device-node在dtb structure内的偏移获得指向device-node的指针

3.5.1.116. fdt_offset_ptr_

//fdt: 指向dtb
//offset: device-node在dtb structure区块内的偏移
static inline const void *fdt_ofset_ptr_(const void *fdt, int offset)
{
    return (const char*)fdt + fdt_off_dt_struct(fdt) + offset;
}

fdt_offset_ptr_ 通过device-node在dtb structure内的偏移得到指向device-node的指针.

注解

dtb的结构涉及如下图所示

boot_param_header

memory reserve map

device-tree structure

device-tree strings

3.5.1.117. fdt_reserved_mem_save_node

#define MAX_RESERVED_REGIONS 32
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
//node: 指向节点偏移
//uname: 指向预留区的名字
//base: 预留区的起始地址
//size: 预留区的长度
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
                    phys_addr_t base, phys_addr_t size)
{
    struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];

    if(reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
        pr_err("not enough space all defined regions.\n");
        return;
    }

    rmem->fdt_node = node;
    rmem->name = uname;
    rmem->base = base;
    rmem->size = size;

    reserved_mem_count++;

    return;
}

fdt_reserved_mem_save_node 用于将dts中”reserved-memory”添加到系统的reserved_mem[]数组中

注解

内核使用一个struct reserved_mem数组维护着系统中所有的保留区

3.5.1.118. FDT_RO_PROBE

#define FDT_RO_PROBE(fdt)   \
{   \
    int err_; \
    if((err_ = fdt_ro_probe_(fdt)) != 0) \
        return err_;    \
}

FDT_RO_PROBE 用于检查dtb的完整性

3.5.1.119. fdt_ro_probe_

int fdt_ro_probe_(const void *fdt)
{
    //检查DTB的MAGIC信息
    if(fdt_magic(fdt) == FDT_MAGIC) {
        if(fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
            return -FDT_ERR_BADVERSION;
        if(fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
            return -FDT_ERR_BADVERSION;
    } else if(fdt_magic(fdt) == FDT_SW_MAGIC) {
        if(fdt_size_dt_struct(fdt) == 0)
            return -FDT_ERR_BADSTATE;
    } else {
        return -FDT_ERR_BADMAGIC;
    }

    return 0;
}

fdt_ro_probe_ 用于一个只读dtb的最小健全性检查.

3.5.1.120. __fdt_scan_reserved_mem

//node: 指向子节点的索引
//uname: 子节点的名字
//depth: 子节点的深度
//data: 私有数据
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
                                    int depth, void *void)
{
    static int found;
    int err;

    //判断节点是否是reserved-memory节点内的子节点
    if(!fount && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
        if(__reserved_mem_check_root(node) != 0) {
            pr_err("reserved memory: unsupported node format, ignoring\n");
            return 1;
        }
        fount = 1;
        return 0;
    } else if(!found) {
        return 0;
    } else if(found && depth < 2) {
        return 1;
    }

    //判断节点的status是否为okay
    if(!of_fdt_device_is_available(initial_boot_params, node))
        return 0;

    //将节点的reg属性对应的预留区加入到MEMBLOCK内存分配器的保留区
    err = __reserved_mem_reserve_reg(node, uname);
    if(err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
        fdt_reserved_mem_save_node(node, uname, 0, 0);

    return 0;
}

__fdt_scan_reserved_mem 用于将dts中reserved-memory节点包含的子节点预留区加入到系统内进行维护.

3.5.1.121. fdt_size_dt_strings

#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))

fdt_size_dt_strings 用于读取dtb header的dt_strings_size信息

3.5.1.122. fdt_size_dt_struct

#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))

fdt_size_dt_struct 用于读取dtb header的dt_struct_size信息

3.5.1.123. fdt_string_eq

static int fdt_string_eq_(const void *fdt, int stroffset, const char *s, int len)
{
    int slen;
    const char *p = fdt_get_string(fdt, stroffset, &slen);

    return p && (slen == len) && (memcmp(p, s, len) == 0);
}

fdt_string_eq_ 用于对比offset对应dtb devicetree strings区域内字符串与参数s给定的字符串是否相等

3.5.1.124. fdt_totalsize

#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))

fdt_totalsize 用于读取dtb header的totalsize信息

3.5.1.125. fill_pmd_pags

static void __init fill_pmd_gaps(void)
{
    struct static_vm *svm;
    struct vm_struct *vm;
    unsigned long addr, next = 0;
    pmd_t *pmd;

    list_for_each_entry(svm, &static_vmlist, list) {
        vm  = &svm->vm;
        addr = (unsigned long)vm->addr;
        if(addr < next)
            continue;

        if((addr & ~PMD_MASK) == SECTION_SIZE) {
            pmd = pmd_off_k(addr);
            if(pmd_none(*pmd))
                pmd_empty_section_gap(addr & PMD_MASK);
        }
        addr += vm->size;
        if((addr & ~PMD_MASK) == SECTION_SIZE) {
            pmd = pmd_off_k(addr) + 1;
            if(pmd_none(*pmd))
                pmd_empty_section_gap(addr);
        }
        next = (addr + PMD_SIZE - 1) & PMD_MASK;
    }
}

fill_pmd_gaps 用于检查静态映射区的虚拟地址,是否存在PMD入口值占用了一个,并且基数PMD入口

3.5.1.126. find_limits

static void __init find_limits(unsigned long *min, unsigned long *max_low, unsigned long *max_high)
{
    *max_low = PFN_DOWN(memblock_get_current_limit());
    *min = PFN_UP(memblock_start_of_DRAM());
    *max_high = PFN_DOWN(memblock_end_of_DRAM());
}

find_limits 获得物理地址低端物理内存的起始页帧和终止页帧以及MEMBLOCK内存分配器支持的最大页帧

3.5.1.127. fix_to_virt

static __always_inline unsigned long fix_to_virt(const unsigned int idx)
{
    BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
    return __fix_to_virt(idx);
}

fix_to_virt 通过FIXMAP索引获得对应的虚拟地址

3.5.1.128. fixmap_pmd

static inline pmd_t * __init fixmap_pmd(unsigned long addr)
{
    pgd_t *pgd = pgd_offset_k(addr);
    pgd_t *pud = pud_offset(pgd, addr);
    pgd_t *pmd = pmd_offset(pud, addr);

    return pmd;
}

fixmap_pmd 用于获得FIXMAP区间虚拟地址对应的PMD入口地址

3.5.1.129. flush_pmd_entry

static inline void flush_pmd_entry(void *pmd)
{
    const unsigned int __tbl_flag = __cpu_tlb_flags;

    tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
    tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);

    if(tlb_flag(TLB_WB))
        dsb(ishst);
}

flush_pmd_entry 的目的是 ‘clean data of unified cache line by mva to poc’