1. 程式人生 > 其它 >arm64記憶體-fdt的對映和setup_machine_fdt

arm64記憶體-fdt的對映和setup_machine_fdt

呼叫順序

arch/arm64/kernel/setup.c

setup_arch -> setup_machine_fdt

setup_machine_fdt

 171static void __init setup_machine_fdt(phys_addr_t dt_phys)
 172{
 173        int size;
 174        void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
 175        const char *name;
 176
 177        if
(dt_virt) 178 memblock_reserve(dt_phys, size); 179 180 if (!dt_virt || !early_init_dt_scan(dt_virt)) { 181 pr_crit("\n" 182 "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" 183 "
The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" 184 "\nPlease check your bootloader.", 185 &dt_phys, dt_virt); 186 187 while (true) 188 cpu_relax(); 189 } 190 191 /* Early fixups are done, map the FDT as read-only now
*/ 192 fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); 193 194 name = of_flat_dt_get_machine_name(); 195 if (!name) 196 return; 197 198 pr_info("Machine model: %s\n", name); 199 dump_stack_set_arch_desc("%s (DT)", name); 200} 201

 

174  使用fixmap_remap_fdt 在 arch/arm64/mm/mmu.c,  將實體地址 dt_phys 對映到虛擬地址 dt_virt , 並且 得到 fdt 的長度 size  (下面會有介紹)

177 ~ 178 如果對映成功,即 dt_virt 不為 0 , 使用memblock 模組的 reserve 函式,將  dt_phys 開始 size 大小的這塊記憶體,在 memblock 模組中 預留下來。

180 在保證 dt_virt 不為0 的前提下面,呼叫 early_init_dt_scan ( dt_virt )   drivers/of/fdt.c 中, 給 fdt 模組填入輸入 dt_virt ,並初始化fdt模組,後面就可以呼叫 fdt 模組的函式,從裡面取屬性了。 (下面會有介紹)

181 ~ 188 如果 early_init_dt_scan 返回false了,表示 dt_virt 指向區域的 裝置樹 格式有問題,報錯。

192 將 dt_phys  開始 size 大小 的這塊記憶體設定為 只讀。

192 呼叫 fdt 模組的 函式,獲取屬性值, machine_name

199 給 dump stack 模組,設定 arch desc ,也就是 machine name 。

 

fixmap_remap_fdt

arch/arm64/mm/mmu.c

1265void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
1266{
1267        const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
1268        int offset;
1269        void *dt_virt;

1297        offset = dt_phys % SWAPPER_BLOCK_SIZE;
1298        dt_virt = (void *)dt_virt_base + offset;
1299
1300        /* map the first chunk so we can read the size from the header */
1301        create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
1302                        dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
1303
1304        if (fdt_magic(dt_virt) != FDT_MAGIC)
1305                return NULL;
1306
1307        *size = fdt_totalsize(dt_virt);
1308        if (*size > MAX_FDT_SIZE)
1309                return NULL;
1310
1311        if (offset + *size > SWAPPER_BLOCK_SIZE)
1312                create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
1313                               round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);
1314
1315        return dt_virt;
1316}

1267 呼叫 fixmap 模組的函式,得到 FIX_FDT 這個 idx 對應的 VA 地址,放在dt_virt_base 裡面。

1270 ~ 1296 跳過一些引數檢查

1297  計算 dt_phys 這個實體地址,以  swapper_block 大小對齊後,在一個swapper_block 中的偏移。

1298 由 dt_virt_base 和 offset 得到 dt_phys 對映後的 VA 地址。 這個地址在 1307 行,作輸入給fdt模組的 fdt_totalsize 函式使用,取得 裝置樹 佔記憶體大小。 1315 行返回值。

 

1301 使用 create_mapping_noalloc 函式,建立 dt_virt_base 到  round_down ( dt_phys, SWAPPER_BLOCK_SIZE ) 之間的 對映關係。

        create_mapping_noalloc 函式 也在  arch/arm64/mm/mmu.c 中,是 static 宣告,相當於一個 建立對映的 輔助函式。

        這個輔助函式會 修改 已經存在  (不會新建)  的 pgd pud pmd pte 表, 表裡面的表項內容,完成 phys 和 virt 之間的對映。

        前提是 fixmap 模組,已經 初始化了,所以 fixmap start  ~  fixmap_top 這段 VA 地址 對應的 pgd pud pmd pte 表 都已經存在了。dt_virt_base 就是處在fixmap start  ~  fixmap_top 這段 VA 地址 之間。

         為什麼使用 本模組中的 static 輔助函式,不使用 fixmap 模組的函式?

        各個軟體模組  歸根到底,都是為了管理 操作   裝置; 各個軟體模組都  都遵從     從裝置讀->算->寫入裝置 的方式,修改裝置的狀態即可,不必太多耦合,一個呼叫另外一個。

 

1034 ~ 1035 檢查  fdt magic 標識。

 

1037~ 1039 取 size ,並對size 進行檢查。

 

1311 ~ 1313 ,發現 offset + size 超過了 一個 swapper block 的大小,則需要對映後面的一個 swapper block ,這樣,才能訪問完整的 裝置樹。

 

early_init_dt_scan

drivers/of/fdt.c

1201bool __init early_init_dt_scan(void *params)
1202{
1203        bool status;
1204
1205        status = early_init_dt_verify(params);
1206        if (!status)
1207                return false;
1208
1209        early_init_dt_scan_nodes();
1210        return true;
1211}

1205  呼叫 early_init_dt_verify 進行 校驗 檢查, 檢查失敗,返回false

1209 呼叫 early_init_dt_scan_nodes 解析 裝置樹的節點。