一、重点内容
- 页表翻译相关的硬件
- 通过软件将物理地址转换为虚拟地址
二、相关硬件
#include <stdio.h>
int main(void)
{
printf("hello world\n");
}
三、物理地址
四、参考源码
#define pr_fmt(fmt) "xxx: " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include "ckret.h"
static void *vaddr;
#define MAGIC_VALUE 0xAABB
/**************************************************************************************************
* @brief : 手动计算物理地址
* @param : None
* @return : 0成功, -1失败
**************************************************************************************************/
static phys_addr_t manu_to_phys(void *addr)
{
pgd_t *pgd, *m_pgd;
p4d_t *p4d, *m_p4d;
pud_t *pud, *m_pud;
pmd_t *pmd, *m_pmd;
pte_t *pte, *m_pte;
phys_addr_t paddr;
/* 通过函数计算 */
pgd = pgd_offset(current->mm, (unsigned long)addr); // 获取pgd
p4d = p4d_offset(pgd, (unsigned long)addr); // 获取p4d
pud = pud_offset(p4d, (unsigned long)addr); // 获取pud
pmd = pmd_offset(pud, (unsigned long)addr); // 获取pmd
pte = pte_offset_map(pmd, (unsigned long)addr); // 获取pte
/* 通过pte转成物理地址 */
paddr = (pte_pfn(*pte) << PAGE_SHIFT) | ((unsigned long)vaddr & ~PAGE_MASK);
pte_unmap(pte);
/* 手动计算 */
unsigned long caddr = (unsigned long)addr;
// long index = (caddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1);
long index = (caddr >> 39) & 0x1FF;
pgd_t *tpgd = current->mm->pgd;
LOG_I("index = %ld, func index = %ld", index, pgd_index(caddr));
LOG_I("my pgd = %p", tpgd + index);
return paddr;
}
/**************************************************************************************************
* @brief : 内存转换测试
* @param : None
* @return : 0成功, -1失败
**************************************************************************************************/
static void mem_transfer_test(void)
{
int val;
void __iomem *map_addr;
phys_addr_t func_paddr, manu_paddr;
/* 内存地址判断 */
vaddr = kmalloc(4096, GFP_KERNEL); // 申请4K大小内存
func_paddr = virt_to_phys(vaddr); // 通过函数计算物理地址
manu_paddr = manu_to_phys(vaddr); // 通过页表计算物理地址
LOG_I("vaddr = %p, func = %llx, manu = %llx", vaddr, func_paddr, manu_paddr);
if(func_paddr == manu_paddr) {
LOG_I("match addr");
} else {
LOG_I("not match addr");
}
/* 物理地址检验 */
*(int *)vaddr = MAGIC_VALUE; // 向虚拟地址写入一个0xAABB 幻数
map_addr = ioremap(func_paddr, sizeof(int)); // 把物理地址转为虚拟地址
val = ioread32(map_addr);
iounmap(map_addr);
if(val == MAGIC_VALUE) {
LOG_I("match value");
}else {
LOG_I("not match value");
}
}
/**************************************************************************************************
* @brief : 模块初始化
* @param : None
* @return : 0成功, -1失败
**************************************************************************************************/
static int __init xxx_init(void)
{
mem_transfer_test();
LOG_I("xxx init.");
return 0;
}
/**************************************************************************************************
* @brief : 模块退出
* @param : None
* @return : 0成功, -1失败
**************************************************************************************************/
static void __exit xxx_exit(void)
{
kfree(vaddr);
LOG_I("xxx exit.");
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZW");
MODULE_DESCRIPTION("kmod - xxmem");