linux内核地址有效性判断方法

如果只是需要大致地判断范围,可以参考内核\linux-3.4.104\Documentation\x86\x86_64\mm.txt中的对各个段的分配的描述。

但是如果需要更加精确地判断,就需要根据内核页表,一级一级地查找,查看是否存在对应的物理地址(内核态的地址不存在SWAP的问题),下面是内核代码段(针对X86-64,有修改)

int kern_addr_valid(unsigned long address)
{
 pgd_t *pgd;
 pud_t *pud;
 pmd_t *pmd;
 pte_t *pte;
 unsigned long high_bits = ((long)address) >> 47;

 if (high_bits != 0 && high_bits != -1UL)
  return 0;/*原因见INTEL相关文档*/
 /*swapper_pg_dir对应的符号init_level4_pgt在有的版本没有导出
 需要用kallsyms_lookup_name获取到该符号的地址*/
 pgd = swapper_pg_dir + pgd_index(address);
 if (pgd_present(*pgd))
  return 0;
 pud = pud_offset(pgd, address);
 if (pud_present(*pud))
  return 0;
 if (pud_large(*pud))
  return pfn_valid(pud_pfn(*pud));
 pmd = pmd_offset(pud, address);
 if (pmd_present(*pmd))
  return 0;
 if (pmd_large(*pmd))
  return pfn_valid(pmd_pfn(*pmd));
 pte = pte_offset_kernel(pmd, address);
 if (pte_present(*pte))
  return 0;
 return pfn_valid(pte_pfn(*pte));
}

以上代码段基本上和内核的中有关于对high_bits的做法,是基于X86-64架构对64位线性地址的处理,当前的架构采用9-9-9-9-12的模式,只是用了48位,就规定:高16bits(48-63)必须和第47bits保持一致。详细的说明参见《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1:Basic Architecture》3.3.7.1  Canonical Addressing:
Intel 64 architecture defines a 64-bit linear address. Implementations can support less. The first implementation 
of IA-32 processors with Intel 64 architecture supportsa 48-bit linear address. This means a canonical address 
must have bits 63 through 48 set to zeros or ones (depending on whether bit 47 is a zero or one).
如果违反该规则,CPU会检查到该错误并发起一个General protection fault

注意:以上的代码,是判断一个地址是否可以读,当然只是保证读的话不产生page fault,可以和magic值一起进一步确认。如果要判断是否可写,需要进一步检查


你可能感兴趣的:(linux内核)