티스토리 뷰
struct mm_struct init_mm = {
.mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, init_mm.mmap_lock),
.pgd = swapper_pg_dir,
void __init __no_sanitize_address setup_arch(char **cmdline_p)
{
// vmlinux.lds.S 에 있는 값을 변수로 옮김
setup_initial_init_mm(_stext, _etext, _edata, _end);
*cmdline_p = boot_command_line;
// Kernel Address Space Layout Randomization
kaslr_init();
// fixmap __end_of_permanent_fixed_addresses ~ __end_of_fixed_addresses 구간을 가상 주소로 매핑
early_fixmap_init();
// 매핑한 공간중 FIX_BTMAP_BEGIN ~ FIX_BTMAP_END 구간을 ioremap 용으로 슬롯에 등록
early_ioremap_init();
// FDT 의 물리주소를 fixmap 에 매핑
// Machine model: linux,dummy-virt 이런식으로 fdt 를 읽을수 있게됨.
setup_machine_fdt(__fdt_pointer);
....
}
early_fixmap_init
fixmap_init 함수가 굉장히 간결해졌다.
원래는 fixmap 을 2M 페이지를 지원했었으나, FDT가 8바이트 정렬이라 2M 경계를 걸칠 수 있어서, 최대 4M 이 매핑되고 캐싱들도 동작이 이상해지기 때문에, FixMap 영역을 4K 단위로만 처리
커널은 5단계pgd > p4d > pud > pmd > pte 까지 페이지 테이블이 확장되었음
FIX_ADDR 이 사이즈가 작아서 하나만 페이지 테이블을 각각 하나씩 사용. 그래서 pmd 까지 하나쓰고 pte 만 while 돌림
// 요런식으로 pud, pmd, pte 를 boot memory 용으로 사용하기 때문에, 별도 페이지 사용하지 않음
static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __page_aligned_bss;
static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
static void __init early_fixmap_init_pmd(pud_t *pudp, unsigned long addr,
unsigned long end)
{
unsigned long next;
pud_t pud = READ_ONCE(*pudp);
pmd_t *pmdp;
if (pud_none(pud))
__pud_populate(pudp, __pa_symbol(bm_pmd),
PUD_TYPE_TABLE | PUD_TABLE_AF);
pmdp = pmd_offset_kimg(pudp, addr);
do {
next = pmd_addr_end(addr, end);
early_fixmap_init_pte(pmdp, addr);
} while (pmdp++, addr = next, addr != end);
}
// FIXMAP 으로 사용할 가상주소는 미리 정해져있음
#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
#define FIXADDR_TOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_TOT_START (FIXADDR_TOP - FIXADDR_TOT_SIZE)
static inline pgd_t *pgd_offset_pgd(pgd_t *pgd, unsigned long address)
{
return (pgd + pgd_index(address));
};
/*
* a shortcut to get a pgd_t in a given mm
*/
#ifndef pgd_offset
#define pgd_offset(mm, address) pgd_offset_pgd((mm)->pgd, (address))
#endif
#define pgd_offset_k(address) pgd_offset(&init_mm, (address))
static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr,
unsigned long end)
{
p4d_t p4d = READ_ONCE(*p4dp);
pud_t *pudp;
if (CONFIG_PGTABLE_LEVELS > 3 && !p4d_none(p4d) &&
p4d_page_paddr(p4d) != __pa_symbol(bm_pud)) {
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
* 16k/4 levels configurations.
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
}
// 여기에 안찍힘. 왜일까?
// pr_info("p4d: %016llx", p4d_val(p4d));
if (p4d_none(p4d)) // 여기에 들어옴. pud 를 부팅용 bm_pud 로 사용함
__p4d_populate(p4dp, __pa_symbol(bm_pud),
P4D_TYPE_TABLE | P4D_TABLE_AF);
pudp = pud_offset_kimg(p4dp, addr);
// [init_pud] pudp: 0xffff800082bfdff8
// pr_info("[init_pud] pudp: 0x%px", pudp);
early_fixmap_init_pmd(pudp, addr, end);
}
void __init early_fixmap_init(void)
{
unsigned long addr = FIXADDR_TOT_START;
unsigned long end = FIXADDR_TOP;
pgd_t *pgdp = pgd_offset_k(addr);
p4d_t *p4dp = p4d_offset_kimg(pgdp, addr);
// addr: 0xffffffffff430000, end: 0xffffffffff800000, pgdp: 0xffff800081cd2078, p4dp: 0xffff800081cd2ff8
// pr_info("addr: 0x%lx, end: 0x%lx, pgdp: 0x%px, p4dp: 0x%px", addr, end, pgdp, p4dp);
early_fixmap_init_pud(p4dp, addr, end);
}
early_ioremap_setup
fixmap BITMAP 영역에 가상주소를 매핑
enum fixed_addresses {
...
FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
/*
* Used for kernel page table creation, so unmapped memory may be used
* for tables.
*/
FIX_PTE,
FIX_PMD,
FIX_PUD,
FIX_P4D,
FIX_PGD,
__end_of_fixed_addresses
};
void __init early_ioremap_setup(void)
{
int i;
for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
WARN_ON_ONCE(prev_map[i]);
slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i);
}
}
pgtable
include/linux/pgtable.h
#ifndef pgd_index
/* Must be a compile-time constant, so implement it as a macro */
#define pgd_index(a) (((a) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
#endif
static inline pgd_t *pgd_offset_pgd(pgd_t *pgd, unsigned long address)
{
return (pgd + pgd_index(address));
};
/*
* a shortcut to get a pgd_t in a given mm
*/
#ifndef pgd_offset
#define pgd_offset(mm, address) pgd_offset_pgd((mm)->pgd, (address))
#endif
/*
* a shortcut which implies the use of the kernel's pgd, instead
* of a process's
*/
#define pgd_offset_k(address) pgd_offset(&init_mm, (address))
fixmap_remap_fdt
// 실제 FDT(Device Tree Blob)의 물리 주소를 해당 가상 주소에 매핑
void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
{
// FDT 용으로 정의된 fixmap 의 가상주소
const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
phys_addr_t dt_phys_base;
int offset;
void *dt_virt;
/*
* Check whether the physical FDT address is set and meets the minimum
* alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
* at least 8 bytes so that we can always access the magic and size
* fields of the FDT header after mapping the first chunk, double check
* here if that is indeed the case.
*/
BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
return NULL;
dt_phys_base = round_down(dt_phys, PAGE_SIZE);
offset = dt_phys % PAGE_SIZE;
dt_virt = (void *)dt_virt_base + offset;
// fdt 가 있는곳에 가상주소를 찾아내서 매핑
/* map the first chunk so we can read the size from the header */
create_mapping_noalloc(dt_phys_base, dt_virt_base, PAGE_SIZE, prot);
if (fdt_magic(dt_virt) != FDT_MAGIC)
return NULL;
*size = fdt_totalsize(dt_virt);
if (*size > MAX_FDT_SIZE)
return NULL;
if (offset + *size > PAGE_SIZE) {
create_mapping_noalloc(dt_phys_base, dt_virt_base,
offset + *size, prot);
}
return dt_virt;
}
'개발 > arm64 linux 6 분석' 카테고리의 다른 글
early_param (setup_arch) (0) | 2025.05.31 |
---|---|
jump_label (setup_arch) (0) | 2025.05.31 |
start_kernel 1 (0) | 2025.05.24 |
proc.S __primary_switch (0) | 2025.05.17 |
proc.S __cpu_setup (0) | 2025.05.10 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- chrome-extension
- it's called a vrpit
- 잘못된 빨간줄
- mysql
- Golang
- print shared_ptr class member variable
- 카카오
- 영상 픽셀화 하기
- boost
- Quest2
- 에러 위치 찾기
- shared_from_this
- 코어 남기기
- cockroach db
- Reciprocal n-body Collision Avoidance
- 클래스 맴버 변수 출력하기
- red underline
- hole-punching
- set value
- Visual Studio
- ad skip
- C++
- 면접
- vr핏
- RVO
- Obstacle Avoidance
- 봄날에 스케치
- SuffixArray
- 우리는 vr핏이라고 부릅니다
- vrpit
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
글 보관함