간단히 말해서, 나는실제 주소커널 내부(또는 9,932,111,872 0x250000000
)는 분명히4KiB로 정렬(페이지 크기). 커널 함수를 사용하여 __va()
얻을 때커널 가상 주소, 비슷한 것을 얻습니다 0xf570660f
(부팅마다 다름).4KiB로 정렬되지 않음.
저는 64비트 시스템이라 HIGHMEM도 없고, 선형 메모리 모델 때문에 4KiB로 정렬된 물리 주소의 가상 주소도 4KiB로 정렬되어야 한다고 생각했습니다. 내가 놓친 게 무엇입니까? 가상 주소는 이어야 하지 않나요 phys_addr + PAGE_OFFSET
? 아니면 sparsemem의 영향인가요? 하지만 아마도 4KiB로 정렬되어야 할까요?
자세한 내용은 다음과 같습니다.
내 작업 환경은 x86 64비트 QEMU VM에 있습니다. 모드에서 PMEM을 DEV-DAX
일반 메모리로 사용하려고 합니다. 물리적 시작 주소( )를 얻을 수 있으며 0x250000000
이는 올바른 것으로 확인되었습니다. 그런 다음 필요에 따라 사용할 수 있도록 커널 공간의 가상 주소로 전송해야 합니다. 다음은 몇 가지 코드입니다.
static long nvpc_map_whole_dev(struct dax_device *dax_dev, void **kaddr, pfn_t *pfn)
{
// get the device
struct dev_dax_nvpc *dax_nvpc = (struct dev_dax_nvpc *)dax_get_private(dax_dev);
// get the virtual address and the pfn_t
*kaddr = __va(dax_nvpc->phys_start);
*pfn = phys_to_pfn_t(dax_nvpc->phys_start, PFN_MAP);
pr_info("[NVPC DEBUG]: paddr %#llx kaddr %p pfn %lu\n", dax_nvpc->phys_start, *kaddr, pfn_t_to_pfn(*pfn));
pr_info("[NVPC DEBUG]: kaddr-paddr %#llx\n", __pa(*kaddr));
return PHYS_PFN(dax_nvpc->size);
}
이것이 내가 얻은 결과입니다:
그림과 같이 , , paddr
dax_nvpc->phys_start
, pfn
모두 맞습니다. 그런데 kaddr
(가상주소가) 헷갈리네요. 그런 다음 이를 kaddr
물리적 주소(다음 출력 라인)로 다시 전송하면 결과가 정확합니다.
더 중요한 것은 페이지 폴트 없이 kaddr
메모리로 무엇이든 할 수 있다는 것입니다 .kaddr + dax_nvpc->size
가상 주소가 4KiB로 정렬되지 않은 이유를 알려줄 수 있는 사람이 있나요? 나는 어딘가에서 바보인가? 또한 가상 주소가 페이지와 정렬되도록 할 수 있는 방법이 있습니까?
답변1
이유 %p
는 빠른 확인을 위해 printk
변경하면 커널 주소 출력이 예상대로 4KB로 정렬되기 때문입니다.%p
%#llx
그 이유는 여기에서 찾을 수 있습니다:커널 문서: printk 형식 포인터 유형. %p
printk는 커널 정보 유출을 방지하기 위해 해시된 포인터 주소를 내부적으로 인쇄합니다. 그래서 포인터가 이상하게 보입니다. 실제 가상 주소를 확인하려면 를 사용 %px
하거나 no_hash_pointers
부팅 매개변수에 추가하면 됩니다. 자세한 사용방법은 링크를 참고해주세요.