
1354 void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
1355 {
1356 const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
dt_virt_base = FIX_FDT의 가상주소
1357 int offset;
1358 void *dt_virt;
1359
1360 /*
1361 * Check whether the physical FDT address is set and meets the minimum
1362 * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
1363 * at least 8 bytes so that we can always access the magic and size
1364 * fields of the FDT header after mapping the first chunk, double check
1365 * here if that is indeed the case.
1366 */
물리적 FDT 주소가 설정되어 있고 최소 정렬 요구 사항을 충족하는지 확인하세요. 첫 번째 청크를 매핑한 후 FDT 헤더의 Magic 및 Size 필드에 항상 액세스할 수 있도록 MIN_FDT_ALIGN이 최소 8바이트가 되도록 의존하고 있으므로 여기에서 실제로 그런 경우인지 다시 확인하세요.
1367 BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
1368 if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
1369 return NULL;
1370
1371 /*
1372 * Make sure that the FDT region can be mapped without the need to
1373 * allocate additional translation table pages, so that it is safe
1374 * to call create_mapping_noalloc() this early.
1375 *
1376 * On 64k pages, the FDT will be mapped using PTEs, so we need to
1377 * be in the same PMD as the rest of the fixmap.
1378 * On 4k pages, we'll use section mappings for the FDT so we only
1379 * have to be in the same PUD.
1380 */
추가 변환 테이블 페이지를 할당할 필요 없이 FDT 영역을 매핑할 수 있는지 확인하여 일찍 create_mapping_noalloc()을 호출하는 것이 안전합니다.
64k 페이지에서 FDT는 PTE를 사용하여 매핑되므로 나머지 fixmap과 동일한 PMD에 있어야 합니다.
4k 페이지에서는 FDT에 섹션 매핑을 사용하므로 동일한 PUD에만 있으면 됩니다.
1381 BUILD_BUG_ON(dt_virt_base % SZ_2M);
dt_virt_base 의 2MB 정렬확인
1382
1383 BUILD_BUG_ON(__fix_to_virt(FIX_FDT_END) >> SWAPPER_TABLE_SHIFT !=
1384 __fix_to_virt(FIX_BTMAP_BEGIN) >> SWAPPER_TABLE_SHIFT);
FIX_FDT_END ~ FIX_BTMAP_BEGIN 범위가 SWAPPER_TABLE_SHIFT 안에 있는지 확인
1385
1386 offset = dt_phys % SWAPPER_BLOCK_SIZE;
1387 dt_virt = (void *)dt_virt_base + offset;
(dt_virt)FIX_FDT의 가상주소와 (dt_phys) fdt의 물리주소를 SWAPPER_BLOCK_SIZE 단위로 끝자리 조정
1388
1389 /* map the first chunk so we can read the size from the header */
1390 create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
1391 dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
1392
1393 if (fdt_magic(dt_virt) != FDT_MAGIC)
1394 return NULL;
정상적인 FDT_MAGIC 코드인지 확인
1395
1396 *size = fdt_totalsize(dt_virt);
1397 if (*size > MAX_FDT_SIZE)
1398 return NULL;
fdt 최대크기 초과 확인
1399
1400 if (offset + *size > SWAPPER_BLOCK_SIZE)
1401 create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
1402 round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);
1403
1404 return dt_virt;
1405 }
444 /*
445 * This function can only be used to modify existing table entries,
446 * without allocating new levels of table. Note that this permits the
447 * creation of new section or page entries.
448 */
이 함수는 새로운 테이블 레벨을 할당하지 않고 기존 테이블 항목을 수정하는 데에만 사용할 수 있습니다. 이를 통해 새 섹션이나 페이지 항목을 생성할 수 있습니다.
449 static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
450 phys_addr_t size, pgprot_t prot)
451 {
452 if ((virt >= PAGE_END) && (virt < VMALLOC_START)) {
453 pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
454 &phys, virt);
455 return;
456 }
457 __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
458 NO_CONT_MAPPINGS);
459 }
395 static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
396 unsigned long virt, phys_addr_t size,
397 pgprot_t prot,
398 phys_addr_t (*pgtable_alloc)(int),
399 int flags)
400 {
401 mutex_lock(&fixmap_lock);
402 __create_pgd_mapping_locked(pgdir, phys, virt, size, prot,
403 pgtable_alloc, flags);
404 mutex_unlock(&fixmap_lock);
405 }
367 static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
368 unsigned long virt, phys_addr_t size,
369 pgprot_t prot,
370 phys_addr_t (*pgtable_alloc)(int),
371 int flags)
372 {
373 unsigned long addr, end, next;
374 pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
init_mm.init_pg_dir 을 PGD로 FIX_FDT를 가상주소로 하는 pgdp 확득.
375
376 /*
377 * If the virtual and physical address don't have the same offset
378 * within a page, we cannot map the region as the caller expects.
379 */
페이지 내에서 가상 주소와 실제 주소의 오프셋이 동일하지 않으면 호출자가 예상하는 대로 지역을 매핑할 수 없습니다.
380 if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
381 return;
382
383 phys &= PAGE_MASK;
384 addr = virt & PAGE_MASK;
385 end = PAGE_ALIGN(virt + size);
물리주소와 가상주소를 Page 단위 내림정렬, end 주소 획득
386
387 do {
388 next = pgd_addr_end(addr, end);
다음 Mapping 주소 획득
389 alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
390 flags);
391 phys += next - addr;
392 } while (pgdp++, addr = next, addr != end);
393 }
394
311 static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
312 phys_addr_t phys, pgprot_t prot,
313 phys_addr_t (*pgtable_alloc)(int),
314 int flags)
315 {
316 unsigned long next;
317 pud_t *pudp;
318 p4d_t *p4dp = p4d_offset(pgdp, addr);
319 p4d_t p4d = READ_ONCE(*p4dp);
FIX_FDT의 가상주소의 p4dp와 p4d 획득
320
321 if (p4d_none(p4d)) {
322 p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN;
323 phys_addr_t pud_phys;
324
325 if (flags & NO_EXEC_MAPPINGS)
326 p4dval |= P4D_TABLE_PXN;
해당 page의 실행 금지를 위해 PXN 속성 설정
327 BUG_ON(!pgtable_alloc);
328 pud_phys = pgtable_alloc(PUD_SHIFT);
329 __p4d_populate(p4dp, pud_phys, p4dval);
p4dp에 배정받은 PUD의 물리주소 pud_phys를 연결
330 p4d = READ_ONCE(*p4dp);
331 }
332 BUG_ON(p4d_bad(p4d));
p4d에 table flag가 설정되어있지 않으면 BUG_ON
333
334 pudp = pud_set_fixmap_offset(p4dp, addr);
FIX_PUD에 addr(FIX_FDT)의 PUD를 만들고 pudp 획득
335 do {
336 pud_t old_pud = READ_ONCE(*pudp);
337
338 next = pud_addr_end(addr, end);
addr의 다음 pudp값 획득
339
340 /*
341 * For 4K granule only, attempt to put down a 1GB block
342 */
Page 크기가 4KB인경우 1GB 블록 사용가능
343 if (pud_sect_supported() &&
344 ((addr | next | phys) & ~PUD_MASK) == 0 &&
345 (flags & NO_BLOCK_MAPPINGS) == 0) {
346 pud_set_huge(pudp, phys, prot);
Page 크기가 4KB이고, addr, next, phys 가 PUD offset 이 0이고, BLOCK Mapping 이 허락된경우, BLOCK Mapping 진행
347
348 /*
349 * After the PUD entry has been populated once, we
350 * only allow updates to the permission attributes.
351 */
352 BUG_ON(!pgattr_change_is_safe(pud_val(old_pud),
353 READ_ONCE(pud_val(*pudp))));
old_pud (huge page 할당전 pud)와 pudp (huge page 할당후)의 mapping attributes를 비교하여 변경가능 범위인지 검사
354 } else {
355 alloc_init_cont_pmd(pudp, addr, next, phys, prot,
356 pgtable_alloc, flags);
357
358 BUG_ON(pud_val(old_pud) != 0 &&
359 pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
360 }
361 phys += next - addr;
362 } while (pudp++, addr = next, addr != end);
363
364 pud_clear_fixmap();
bm_pte에서 FIX_PUD 연결 해제
365 }
1407 int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
1408 {
1409 pud_t new_pud = pfn_pud(__phys_to_pfn(phys), mk_pud_sect_prot(prot));
1410
1411 /* Only allow permission changes for now */
1412 if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)),
1413 pud_val(new_pud)))
1414 return 0;
이전 상태에서 새로 바꾸려는 상태로 바꾸는 것이 오류를 발생 시키지 않는지 검사
1415
1416 VM_BUG_ON(phys & ~PUD_MASK);
물리 주소가 PUD 정렬이 되었는지 검사
1417 set_pud(pudp, new_pud);
1418 return 1;
1419 }
270 static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
271 unsigned long end, phys_addr_t phys,
272 pgprot_t prot,
273 phys_addr_t (*pgtable_alloc)(int), int flags)
274 {
275 unsigned long next;
276 pud_t pud = READ_ONCE(*pudp);
277
278 /*
279 * Check for initial section mappings in the pgd/pud.
280 */
281 BUG_ON(pud_sect(pud));
CONT Mapping 을 하려는 곳이라 Section Mapping 설정이면 오류
282 if (pud_none(pud)) {
283 pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN;
커널 영역 관리에 사용되기에 UXN 설정
284 phys_addr_t pmd_phys;
285
286 if (flags & NO_EXEC_MAPPINGS)
287 pudval |= PUD_TABLE_PXN;
288 BUG_ON(!pgtable_alloc);
289 pmd_phys = pgtable_alloc(PMD_SHIFT);
290 __pud_populate(pudp, pmd_phys, pudval);
291 pud = READ_ONCE(*pudp);
292 }
293 BUG_ON(pud_bad(pud));
294
295 do {
296 pgprot_t __prot = prot;
297
298 next = pmd_cont_addr_end(addr, end);
299
300 /* use a contiguous mapping if the range is suitably aligned */
301 if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
302 (flags & NO_CONT_MAPPINGS) == 0)
303 __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
addr, next, phys가 PMD상 CONT Mapping이 가능하고 CONT Mapping 불가 설정이 아니면 CONT Mapping
304
305 init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
306
307 phys += next - addr;
308 } while (addr = next, addr != end);
309 }
233 static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
234 phys_addr_t phys, pgprot_t prot,
235 phys_addr_t (*pgtable_alloc)(int), int flags)
236 {
237 unsigned long next;
238 pmd_t *pmdp;
239
240 pmdp = pmd_set_fixmap_offset(pudp, addr);
FIX_PMD사용하기 위해 bm_pte에 연결하고
241 do {
242 pmd_t old_pmd = READ_ONCE(*pmdp);
243
244 next = pmd_addr_end(addr, end);
245
246 /* try section mapping first */
247 if (((addr | next | phys) & ~PMD_MASK) == 0 &&
248 (flags & NO_BLOCK_MAPPINGS) == 0) {
249 pmd_set_huge(pmdp, phys, prot);
PMD가 BLOCK Mapping 가능한 경우
250
251 /*
252 * After the PMD entry has been populated once, we
253 * only allow updates to the permission attributes.
254 */
255 BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd),
256 READ_ONCE(pmd_val(*pmdp))));
257 } else {
258 alloc_init_cont_pte(pmdp, addr, next, phys, prot,
259 pgtable_alloc, flags);
260
261 BUG_ON(pmd_val(old_pmd) != 0 &&
262 pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
pte 할당후 pmd 값이 변경된경우 BUG_ON
263 }
264 phys += next - addr;
265 } while (pmdp++, addr = next, addr != end);
266
267 pmd_clear_fixmap();
FIX_PMD 을 bm_pte 에서 연결해제
268 }
194 static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
195 unsigned long end, phys_addr_t phys,
196 pgprot_t prot,
197 phys_addr_t (*pgtable_alloc)(int),
198 int flags)
199 {
200 unsigned long next;
201 pmd_t pmd = READ_ONCE(*pmdp);
202
203 BUG_ON(pmd_sect(pmd));
section mapping 인경우 BUG_ON
204 if (pmd_none(pmd)) {
205 pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN;
206 phys_addr_t pte_phys;
207
208 if (flags & NO_EXEC_MAPPINGS)
209 pmdval |= PMD_TABLE_PXN;
실행금지 인경우 PXN설정
210 BUG_ON(!pgtable_alloc);
211 pte_phys = pgtable_alloc(PAGE_SHIFT);
212 __pmd_populate(pmdp, pte_phys, pmdval);
213 pmd = READ_ONCE(*pmdp);
214 }
215 BUG_ON(pmd_bad(pmd));
216
217 do {
218 pgprot_t __prot = prot;
219
220 next = pte_cont_addr_end(addr, end);
221
222 /* use a contiguous mapping if the range is suitably aligned */
223 if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
224 (flags & NO_CONT_MAPPINGS) == 0)
addr, next, phys 가 PTE CONT (16page) 만큼 정렬되어 있고, CONT Mapping 금지가 아니라면 CONT Mapping
225 __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
226
227 init_pte(pmdp, addr, next, phys, __prot);
228
229 phys += next - addr;
230 } while (addr = next, addr != end);
231 }
170 static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
171 phys_addr_t phys, pgprot_t prot)
172 {
173 pte_t *ptep;
174
175 ptep = pte_set_fixmap_offset(pmdp, addr);
176 do {
177 pte_t old_pte = READ_ONCE(*ptep);
178
179 set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));
FIX_PTE(가상주소) 와 fdt (물리주소)를 연결
180
181 /*
182 * After the PTE entry has been populated once, we
183 * only allow updates to the permission attributes.
184 */
185 BUG_ON(!pgattr_change_is_safe(pte_val(old_pte),
186 READ_ONCE(pte_val(*ptep))));
pte 상태값 변경이 오류를 이르키지 않는지 검사
187
188 phys += PAGE_SIZE;
189 } while (ptep++, addr += PAGE_SIZE, addr != end);
190
191 pte_clear_fixmap();
FIX_PTE 를 bm_pte에서 해제
192 }
'linux' 카테고리의 다른 글
6.1/early_ioremap_init(void) (0) | 2025.03.29 |
---|---|
6.1/setup_arch(char **cmdline_p) (0) | 2024.04.02 |
6.1/early_fixmap_init(void) (0) | 2023.12.18 |
6.1/early_fdt_map(u64 dt_phys) (0) | 2023.12.18 |
6.1/Head.S (0) | 2023.11.16 |