亚洲欧洲国产欧美一区精品,激情五月亚洲色五月,最新精品国偷自产在线婷婷,欧美婷婷丁香五月天社区

      考試首頁 | 考試用書 | 培訓(xùn)課程 | 模擬考場 | 考試論壇  
        當(dāng)前位置:操作系統(tǒng) > Linux > 文章內(nèi)容
        

      Linux基礎(chǔ)教程:Linux設(shè)備樹(Devicetree)

       [ 2016年2月18日 ] 【

      memory&chosen節(jié)點

      根節(jié)點那一節(jié)我們說過,最簡單的設(shè)備樹也必須包含cpus節(jié)點和memory節(jié)點。memory節(jié)點用來描述硬件內(nèi)存布局的。如果有多塊內(nèi)存,既可以通過多個memory節(jié)點表示,也可以通過一個memory節(jié)點的reg屬性的多個元素支持。舉一個例子,假如某個64位的系統(tǒng)有兩塊內(nèi)存,分別是

      • RAM: 起始地址 0x0, 長度 0x80000000 (2GB)
      • RAM: 起始地址 0x100000000, 長度 0x100000000 (4GB)

      對于64位的系統(tǒng),根節(jié)點的#address-cells屬性和#size-cells屬性都設(shè)置成2。一個memory節(jié)點的形式如下(還記得前幾節(jié)說過節(jié)點地址必須和reg屬性第一個地址相同的事情吧):
          memory@0 {
              device_type = "memory";
              reg = <0x000000000 0x00000000 0x00000000 0x80000000
                    0x000000001 0x00000000 0x00000001 0x00000000>;
          };

      兩個memory節(jié)點的形式如下:
          memory@0 {
              device_type = "memory";
              reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
          };
          memory@100000000 {
              device_type = "memory";
              reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
          };

      chosen節(jié)點也位于根節(jié)點下,該節(jié)點用來給內(nèi)核傳遞參數(shù)(不代表實際硬件)。對于Linux內(nèi)核,該節(jié)點下最有用的屬性是bootargs,該屬性的類型是字符串,用來向Linux內(nèi)核傳遞cmdline。規(guī)范中還定義了stdout-path和stdin-path兩個可選的、字符串類型的屬性,這兩個屬性的目的是用來指定標準輸入輸出設(shè)備的,在linux中,這兩個屬性基本不用。

      memory和chosen節(jié)點在內(nèi)核初始化的代碼都位于 start_kernel()->setup_arch()->setup_machine_fdt()->early_init_dt_scan_nodes() 函數(shù)中(位于drivers/of/fdt.c),復(fù)制代碼如下(本節(jié)所有代碼都來自官方內(nèi)核4.4-rc7版本):

      1078 void __init early_init_dt_scan_nodes(void)
      1079 {     
      1080    /* Retrieve various information from the /chosen node */
      1081    of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
      1082
      1083    /* Initialize {size,address}-cells info */
      1084    of_scan_flat_dt(early_init_dt_scan_root, NULL);
      1085
      1086    /* Setup memory, calling early_init_dt_add_memory_arch */
      1087    of_scan_flat_dt(early_init_dt_scan_memory, NULL);
      1088 }

      of_scan_flat_dt函數(shù)掃描整個設(shè)備樹,實際的動作是在回調(diào)函數(shù)中完成的。第1081行是對chosen節(jié)點操作,該行代碼的作用是將節(jié)點下的bootargs屬性的字符串拷貝到boot_command_line指向的內(nèi)存中。boot_command_line是內(nèi)核的一個全局變量,在內(nèi)核的多處都會用到。第1084行是根據(jù)根節(jié)點的#address-cells屬性和#size-cells屬性初始化全局變量 dt_root_size_cells和dt_root_addr_cells,還記得前邊說過如果沒有設(shè)置屬性的話就用默認值,這些都在 early_init_dt_scan_root函數(shù)中實現(xiàn)。第1087行是對內(nèi)存進行初始化,復(fù)制early_init_dt_scan_memory 部分代碼如下:

       893 /**
       894  * early_init_dt_scan_memory - Look for an parse memory nodes
       895  */
       896 int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
       897                      int depth, void *data)
       898 {
       899    const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
       900    const __be32 *reg, *endp;
       901    int l;
       902
       903    /* We are scanning "memory" nodes only */
       904    if (type == NULL) {
       905        /*
       906          * The longtrail doesn't have a device_type on the
       907          * /memory node, so look for the node called /memory@0.
       908          */
       909        if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
       910            return 0;
       911    } else if (strcmp(type, "memory") != 0)
       912        return 0;
       913
       914    reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
       915    if (reg == NULL)
       916        reg = of_get_flat_dt_prop(node, "reg", &l);
       917    if (reg == NULL)
       918        return 0;
       919
       920    endp = reg + (l / sizeof(__be32));
       921
       922    pr_debug("memory scan node %s, reg size %d,\n", uname, l);
       923
       924    while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
       925        u64 base, size;
       926
       927        base = dt_mem_next_cell(dt_root_addr_cells, ®);
       928        size = dt_mem_next_cell(dt_root_size_cells, ®);
       929
       930        if (size == 0)
       931            continue;
       932        pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
       933            (unsigned long long)size);
       934
       935        early_init_dt_add_memory_arch(base, size);
       936    }
       937
       938    return 0;
       939 }

      第914行可以看出linux內(nèi)核不僅支持reg屬性,也支持linux,usable-memory屬性。對于 dt_root_addr_cells和dt_root_size_cells的使用也能看出根節(jié)點的#address-cells屬性和#size- cells屬性都是用來描述內(nèi)存地址和大小的。得到每塊內(nèi)存的起始地址和大小后,在第935行調(diào)用 early_init_dt_add_memory_arch函數(shù),復(fù)制代碼如下:
       
       983 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
       984 {
       985    const u64 phys_offset = __pa(PAGE_OFFSET);
       986
       987    if (!PAGE_ALIGNED(base)) {
       988        if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
       989            pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
       990                base, base + size);
       991            return;
       992        }
       993        size -= PAGE_SIZE - (base & ~PAGE_MASK);
       994        base = PAGE_ALIGN(base);
       995    }
       996    size &= PAGE_MASK;
       997
       998    if (base > MAX_MEMBLOCK_ADDR) {
       999        pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
      1000                base, base + size);
      1001        return;
      1002    }
      1003
      1004    if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
      1005        pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
      1006                ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
      1007        size = MAX_MEMBLOCK_ADDR - base + 1;
      1008    }
      1009
      1010    if (base + size < phys_offset) {
      1011        pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
      1012                base, base + size);
      1013        return;
      1014    }
      1015    if (base < phys_offset) {
      1016        pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
      1015    if (base < phys_offset) {
      1016        pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
      1017                base, phys_offset);
      1018        size -= phys_offset - base;
      1019        base = phys_offset;
      1020    }
      1021    memblock_add(base, size);
      1022 }

      從以上代碼可以看出內(nèi)核對地址和大小做了一系列判斷后,最后調(diào)用memblock_add將內(nèi)存塊加入內(nèi)核。

      首頁 1 2 3 4 5 6 7 8 尾頁
      將考試網(wǎng)添加到收藏夾 | 每次上網(wǎng)自動訪問考試網(wǎng) | 復(fù)制本頁地址,傳給QQ/MSN上的好友 | 申請鏈接 | 意見留言 TOP
      關(guān)于本站  網(wǎng)站聲明  廣告服務(wù)  聯(lián)系方式  站內(nèi)導(dǎo)航  考試論壇
      Copyright © 2007-2013 中華考試網(wǎng)(Examw.com) All Rights Reserved