You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核C程序逻辑地址转物理地址报错及段错误修复求助

修复后的完整代码
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/highmem.h>

static unsigned long vaddr2paddr(struct seq_file *m, unsigned long vaddr, int pid)
{
    pte_t *pte_tmp = NULL;  
    pmd_t *pmd_tmp = NULL;  
    pud_t *pud_tmp = NULL;
    p4d_t *p4d_tmp = NULL; 
    pgd_t *pgd_tmp = NULL;  
    struct task_struct *pcb_tmp = NULL;
    struct pid *pid_struct = NULL;
    unsigned long paddr = 0;
    unsigned long pfn;

    printk(KERN_INFO "in vaddr2paddr try to find the task %d .\n", pid);  
    pid_struct = find_get_pid(pid);
    if (!pid_struct) {
        printk(KERN_INFO "Invalid pid %d .\n", pid);
        return 0;
    }

    pcb_tmp = pid_task(pid_struct, PIDTYPE_PID); 
    if (!pcb_tmp) {
        printk(KERN_INFO "Can't find the task %d .\n", pid);
        put_pid(pid_struct);
        return 0;
    }

    /* 排除内核线程,内核线程没有用户地址空间 */
    if (!pcb_tmp->mm) {
        printk(KERN_INFO "Task %d is kernel thread, no user mm .\n", pid);
        put_pid(pid_struct);
        return 0;
    }

    /* 遍历页表前持读锁,防止页表被并发修改 */
    mmap_read_lock(pcb_tmp->mm);
    
    pgd_tmp = pgd_offset(pcb_tmp->mm, vaddr);
    if (pgd_none(*pgd_tmp) || pgd_bad(*pgd_tmp)) {
        printk("not mapped in pgd\n");
        goto out_unlock;
    }

    p4d_tmp = p4d_offset(pgd_tmp, vaddr);
    if (p4d_none(*p4d_tmp) || p4d_bad(*p4d_tmp)) {
        printk("not mapped in p4d\n");
        goto out_unlock;
    }
    
    pud_tmp = pud_offset(p4d_tmp, vaddr);  
    if (pud_none(*pud_tmp) || pud_bad(*pud_tmp)) {
        printk("not mapped in pud\n");
        goto out_unlock;
    }

    pmd_tmp = pmd_offset(pud_tmp, vaddr);
    if (pmd_none(*pmd_tmp) || pmd_bad(*pmd_tmp)) {
        printk("not mapped in pmd\n");
        goto out_unlock;
    }

    /* 用户地址空间pte用pte_offset_map映射后访问,不能用内核专用的pte_offset_kernel */
    pte_tmp = pte_offset_map(pmd_tmp, vaddr);    
    if (pte_none(*pte_tmp) || !pte_present(*pte_tmp)) {
        printk("not mapped in pte or paged out\n");
        goto out_unmap;
    }

    /* 计算物理地址:页帧号左移页大小位 + 页内偏移 */
    pfn = pte_pfn(*pte_tmp);
    paddr = (pfn << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);

out_unmap:
    pte_unmap(pte_tmp);
out_unlock:
    mmap_read_unlock(pcb_tmp->mm);
    put_pid(pid_struct);
    return paddr;
}
核心修改点
  • 补全P4D页表层遍历逻辑,匹配新版内核五级页表接口要求,解决编译类型不匹配错误
  • 增加pid有效性校验、pid引用计数释放逻辑,避免无效pid访问和资源泄漏
  • 增加内核线程判断,内核线程无用户地址空间,直接返回避免空指针访问
  • 新增mmap_lock读锁保护,遍历页表过程中禁止系统修改/回收页表,解决段错误问题
  • 替换内核专用的pte_offset_kernel为用户地址空间适用的pte_offset_map,访问结束后调用pte_unmap释放映射
  • 增加各层页表项的bad校验,避免访问损坏的页表项
  • 补充物理地址计算逻辑,通过页帧号加页内偏移得到最终物理地址
  • 统一错误返回值为0(合法物理地址不可能为0),避免类型转换异常

内容的提问来源于stack exchange,提问作者Su.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:27:03