linux内核对于指令异常的处理

2023-11-15

1.处理流程


以arm64来介绍一下流程,如果在用户层发生指令异常时,首先进入入口el0_undef

( arch/arm64/kernel/entry.s )

el0_undef:
    /*
     * Undefined instruction
     */
    // enable interrupts before calling the main handler
    enable_dbg_and_irq
    ct_user_exit
    mov x0, sp
    bl  do_undefinstr-----------------------------------调用此函数如下
    b   ret_to_user

( arch/arm64/kernel/traps.c )

asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
    siginfo_t info;
    void __user *pc = (void __user *)instruction_pointer(regs);

    /* check for AArch32 breakpoint instructions */
    if (!aarch32_break_handler(regs))
        return;

    if (call_undef_hook(regs) == 0)----------------------进入此函数执行真正的处理过程,正确处理完后,直接返回不进入Oops,相反会出错
        return;

    if (unhandled_signal(current, SIGILL) && show_unhandled_signals_ratelimited()) {
        pr_info("%s[%d]: undefined instruction: pc=%p\n",
            current->comm, task_pid_nr(current), pc);
        dump_instr(KERN_INFO, regs);
    }

    info.si_signo = SIGILL;
    info.si_errno = 0;
    info.si_code  = ILL_ILLOPC;
    info.si_addr  = pc;

    arm64_notify_die("Oops - undefined instruction", regs, &info, 0);
}

( arch/arm64/kernel/traps.c )

static int call_undef_hook(struct pt_regs *regs)
{
    struct undef_hook *hook;
    unsigned long flags;
    u32 instr;
    int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
    void __user *pc = (void __user *)instruction_pointer(regs);

    if (!user_mode(regs))
        return 1;

    if (compat_thumb_mode(regs)) {
        /* 16-bit Thumb instruction */
        if (get_user(instr, (u16 __user *)pc))
            goto exit;
        instr = le16_to_cpu(instr);
        if (aarch32_insn_is_wide(instr)) {
            u32 instr2;

            if (get_user(instr2, (u16 __user *)(pc + 2)))
                goto exit;
            instr2 = le16_to_cpu(instr2);
            instr = (instr << 16) | instr2;
        }
    } else {
        /* 32-bit ARM instruction */
        if (get_user(instr, (u32 __user *)pc))
            goto exit;
        instr = le32_to_cpu(instr);
    }

    raw_spin_lock_irqsave(&undef_lock, flags);
    list_for_each_entry(hook, &undef_hook, node)--------------遍历链表undef_hook中的每一个hook
        if ((instr & hook->instr_mask) == hook->instr_val &&
            (regs->pstate & hook->pstate_mask) == hook->pstate_val)
            fn = hook->fn;----------------------------匹配成功后把hook->fn赋给fn

    raw_spin_unlock_irqrestore(&undef_lock, flags);
exit:
    return fn ? fn(regs, instr) : 1;--------------------------执行fn,正确执行返回0
}

2.未定义指令的注册


结构体struct undef_hook用来封装一个未定义指令

struct undef_hook {
    struct list_head node;
    u32 instr_mask;---------------instruction mask匹配用的掩码
    u32 instr_val;----------------instruction val匹配的关键值
    u64 pstate_mask;
    u64 pstate_val;
    int (*fn)(struct pt_regs *regs, u32 instr);--相关的处理函数
};

如果想要把一个指令加入到内核的未定义指令处理框架中,要先实现一个结构体insn_emulation_ops

struct insn_emulation_ops {
    const char      *name;
    enum legacy_insn_status status;--有两种:INSN_DEPRECATED和INSN_OBSOLETE
    struct undef_hook   *hooks;--
    int         (*set_hw_mode)(bool enable);
};

在这里对于未定义指令可以有两种方式:
(1)INSN_DEPRECATED : 表示指令虽然未定义,但是可以进行处理来使这条指令得以正确执行
(2)INSN_OBSOLETE : 表示指令没有定义,不注册入异常指令处理框架中

2.1 异常指令注册函数

( arch/arm64/kernel/armv8_deprecated.c )

static void register_insn_emulation(struct insn_emulation_ops *ops)
{
    unsigned long flags;
    struct insn_emulation *insn;

    insn = kzalloc(sizeof(*insn), GFP_KERNEL);
    insn->ops = ops;
    insn->min = INSN_UNDEF;

    switch (ops->status) {
    case INSN_DEPRECATED:
        insn->current_mode = INSN_EMULATE;
        /* Disable the HW mode if it was turned on at early boot time */
        run_all_cpu_set_hw_mode(insn, false);
        insn->max = INSN_HW;
        break;
    case INSN_OBSOLETE:
        insn->current_mode = INSN_UNDEF;
        insn->max = INSN_EMULATE;
        break;
    }

    raw_spin_lock_irqsave(&insn_emulation_lock, flags);
    list_add(&insn->node, &insn_emulation);----------把定义的异常指令加入到链表insn_emulation中
    nr_insn_emulated++;
    raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);

    /* Register any handlers if required */
    update_insn_emulation_mode(insn, INSN_UNDEF);----把待处理的异常指令注册到框架中
}

( arch/arm64/kernel/armv8_deprecated.c )

static int update_insn_emulation_mode(struct insn_emulation *insn,
                       enum insn_emulation_mode prev)
{
    int ret = 0;

    switch (prev) {
    case INSN_UNDEF: /* Nothing to be done */
        break;
    case INSN_EMULATE:
        remove_emulation_hooks(insn->ops);
        break;
    case INSN_HW:
        if (!run_all_cpu_set_hw_mode(insn, false))
            pr_notice("Disabled %s support\n", insn->ops->name);
        break;
    }

    switch (insn->current_mode) {
    case INSN_UNDEF:
        break;
    case INSN_EMULATE:
        register_emulation_hooks(insn->ops);----如果指令是可以仿真(也就是可以正常执行的),就调用此函数进行注册
        break;
    case INSN_HW:
        ret = run_all_cpu_set_hw_mode(insn, true);
        if (!ret)
            pr_notice("Enabled %s support\n", insn->ops->name);
        break;
    }

    return ret;
}
static void register_emulation_hooks(struct insn_emulation_ops *ops)
{
    struct undef_hook *hook;

    BUG_ON(!ops->hooks);

    for (hook = ops->hooks; hook->instr_mask; hook++)
        register_undef_hook(hook);

    pr_notice("Registered %s emulation handler\n", ops->name);
}

整个注册流程最终就是要调用register_undef_hook来进行注册

( arch/arm64/kernel/traps.c )

void register_undef_hook(struct undef_hook *hook)
{
    unsigned long flags;

    raw_spin_lock_irqsave(&undef_lock, flags);
    list_add(&hook->node, &undef_hook);---------加入到链表undef_hook
    raw_spin_unlock_irqrestore(&undef_lock, flags);
}

2.2 内核初始化注册入口

late_initcall(armv8_deprecated_init);

static int __init armv8_deprecated_init(void)
{
    if (IS_ENABLED(CONFIG_SWP_EMULATION))
        register_insn_emulation(&swp_ops);

    if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
        register_insn_emulation(&cp15_barrier_ops);

    if (IS_ENABLED(CONFIG_SETEND_EMULATION)) {
        if(system_supports_mixed_endian_el0())
            register_insn_emulation(&setend_ops);
        else
            pr_info("setend instruction emulation is not supported on the system");
    }

    register_cpu_notifier(&insn_cpu_hotplug_notifier);
    register_insn_emulation_sysctl(ctl_abi);

    return 0;
}

change log


date content linux
2017.1.11 linux 4.4
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux内核对于指令异常的处理 的相关文章

  • 一文让你彻底了解Linux内核文件系统

    一 文件系统特点 文件系统要有严格的组织形式 使得文件能够以块为单位进行存储 文件系统中也要有索引区 用来方便查找一个文件分成的多个块都存放在了什么位置 如果文件系统中有的文件是热点文件 近期经常被读取和写入 文件系统应该有缓存层 文件应该
  • 臻识车牌识别摄像头对接

    一 臻识车牌识别摄像头 1 非常有用的官方代码 内部有TCP HTTP等协议 2 官方常见问题 3 官方下载专区 二 http对接例子 1 自己使用java mock 模拟后台服务 你会用到的配置文件 java jar moco runne
  • Linux下SUDO出现Unable to resolve host XXX解决方法

    转载 Ubuntu环境 假设这台机器名字叫abc 机器的hostname 每次执行sudo 就出现这个警告讯息 sudo unable to resolve host abc 虽然sudo 还是可以正常执行 但是警告讯息每次都出来 而这只是
  • file_operations 结构体

    file operations 结构体中的成员函数是字符设备驱动程序设计的主体内容 这些函数实际会在应用程序进行 Linux 的 open write read close 等系统调用时最终被调用 file operations 结构体目前
  • make -C $(LINUX_KERNEL_PATH) M=$(PWD) modules中的M选项

    新的内核模块编程中的make命令里有个M选项 如下 make C lib modules shell uname r build M PWD modules M PWD 意思是返回到当前目录继续读入 执行当前的Makefile 请参考 从
  • 理解virt res shr之间的关系 - linux

    转自 https www orchome com 298 想必在linux上写过程序的同学都有分析进程占用多少内存的经历 或者被问到这样的问题 你的程序在运行时占用了多少内存 物理内存 通常我们可以通过top命令查看进程占用了多少内存 这里
  • docker教程:从头基于空镜像scratch创建一个新的Docker镜像

    从头基于空镜像scratch创建一个新的Docker镜像 我们在使用dockerfile构建镜像时 一种方式是使用预制镜像 这样可以省很多工作量 但问题是镜像会变得特别大 尤其是安装一些应用程序所需的依赖后 镜像的尺寸会更大 如果我们的需求
  • 在Fedora16中安装Qt

    首先 在http www trolltech com download上下载linux下的qt源文件 我下载时最新版是 qt everywhere opensource src 4 7 4 tar gz 将该文件放到某个目录下 进行解压缩
  • 鼠标点击页面出现富强自由等文字JS特效

    在其他博客看到一款JS特效 感觉很不错 所有网上收集过来分享给大家 效果参考本网站 添加点击特效 点击页面会显示 富强 民主 文明 和谐 自由 平等 公正 法治 爱国 敬业 诚信 友善 把以下代码添加到当前主题的head php或foote
  • 七种Linux设备驱动模型之——Device

    前言 Linux将所有的设备统一抽象为struct device结构 同时将所有的驱动统一抽象为struct device driver结构 这样设计之后就方便驱动开发工程师编写驱动 只需要将具体的设备包含struct device结构 具
  • Linux内核分析:输入输出,字符与块设备 31-35

    CPU 并不直接和设备打交道 它们中间有一个叫作设备控制器 Device Control Unit 的组件 例如硬盘有磁盘控制器 USB 有 USB 控制器 显示器有视频控制器等 这些控制器就像代理商一样 它们知道如何应对硬盘 鼠标 键盘
  • 挂载mount问题“wrong fs type, bad option, bad superblock on ”的解决办法

    重装系统后挂载一般会出现如下问题 problem ivy ivy OptiPlex 380 source sudo mount 192 168 9 18 home deep dev env source mount wrong fs typ
  • Centos7.4制作简易RPM包

    准备nginx 1 10 1 tar gz 准备php 7 1 7 tar bz2 这两个源码编译tar包 1 准备制作环境 yum y install rpm build 安装rpm build软件 rpmbuild ba xx spec
  • Linux生产者消费者模型(POSIX信号量)

    目录 一 生产者消费者模型 1 基本概念 2 模型特点 3 模型优点 二 基于BlockingQueue的生产者消费者模型 1 基本概念 2 单生产者 单消费者为例进行模拟实现 3 基于计算任务的生产者消费者模型 三 POSIX信号量 1
  • VSCode:Remote-SSH配置实录

    转自 VSCode Remote SSH配置实录 六天 CSDN博客 也可以通过这样一步步输入用户名和密码链接 为什么要使用VSCode Remote SSH 服务器很多时候都是部署在Linux远程机器上的 我们通常是SSH连过去然后用vi
  • dracut 基本介绍

    dracut 基本介绍 dracut 维基 https dracut wiki kernel org index php Main Page http www 360doc com content 13 0428 09 12139495 2
  • 多线程(1):互斥锁

    leetcode 1114题 按序打印 给你一个类 public class Foo public void first print first public void second print second public void thi
  • int $0x80系统调用的idea

    1 基础知识 用户态和内核态 一般现代CPU都有几种不同的指令执行级别 Linux总共划分为4个指令执行级别 内核运行在0级别上 1 2级别默认不运行 用户程序运行在3级别上 在内核指令执行级别上 代码可以执行特权指令 访问任意的物理地址
  • begin to drop messages due to rate-limiting

    对于syslog保存的日志会有很多重要信息 但是一旦打印的日志数量超过设置的阈值 就会丢掉 imuxsock pid 48 begin to drop messages due to rate limiting 这是在调试时不愿看到的 可以
  • 树莓派内核开发准备(内核源码获取、启动过程、源码目录树)

    目录 1 交叉编译工具的安装 2 内核源码获取 3 嵌入式设备带操作系统的启动过程扫盲 4 Linux内核源码树扫盲 1 内核源码简介 2 Linux内核源代码目录树结构 tree指令查看 内核源码目录树 1 交叉编译工具的安装 参照我之前

随机推荐

  • 机器学习基础学习-多元线性回归问题(梯度下降法实现)

    1 基本概念 在之前的博客当中描述了怎样模拟出了梯度下降的过程 如果是多维情况 theta其实是一个向量 那么对其求导的损失函数也是向量 梯度就是损失函数对每个方向的theta求偏导 和之前的一维线性回归相比 我们对只是对w这个数字进行求导
  • VC++ CComboBox自绘(颜色下拉列表框)

    使用前 请将控件的Style属性设置为DropdownList 下拉列表 Owner Draw设置为Fixed Has Strings设置为TRUE 效果图如下 头文件声明 CSWColorComboBox h pragma once in
  • 关于C++ 对象私有成员不可访问的理解误区

    C 中对象的私有成员是否可以被别的对象访问 答案是肯定的 但是分场合 同一个类 友元类 什么情况下可以访问C 对象的私有成员呢 首先 C 私有成员不可以直接访问是个错误理解 C 对象的私有成员在类内是可以访问的 请注意是类内而不仅仅是对象内
  • Flink自定义实现ElasticSearch Table Source

    Flink版本 1 12 1 ES Maven版本 elasticsearch rest client 6 3 1 FLINK TableSource官方文档 https ci apache org projects flink flink
  • minio搭建图床 配合typora实现写博客图片自动上传

    minio搭建图床 配合typora实现写博客图片自动上传 1 搭建minio 查看博客 http www weinigb cn info blogOid 32 2 使用脚本 python 使用之前需要添加依赖 分别需要添加 minio r
  • Binder (一) mmap与一次拷贝原理

    Binder机制 跨进程通信IPC 远程过程调用手段RPC 4个角色进行粘合 Client Server Service Manager和Binder驱动程序 整个过程只需要一次拷贝 Binder Driver misc设备 dev bin
  • 【已更新】2023电工杯数学建模B题完整代码 持续更新

    已给出第一问详细代码 完整获取链接为 https mbd pub o bread ZJmXmpxt import pandas as pd import numpy as np from sklearn preprocessing impo
  • TCP与UDP协议

    TCP与UDP协议 TCP报文格式 UDP报文格式 TCP与UDP协议的比较 TCP报文格式 源端口 2字节 标识报文的返回地址 目的端口 2字节 指明接收方计算机上的应用程序接口 序号 4字节 大约21亿的范围 序号 即seq 指明本报文
  • 中国人的开源[转]

    中国人的开源 何谓开源 顾名就可以思意 开放源码 国外的开源社区比国内起步早是事实 而国内某些知名人士口口声声说中国的开源需要开源基金 需要支持 基金有了 出现了中国人的开源社区 并且建立了旗下网站 这样就是中国人的开源了 某个开源社区里经
  • C语言-程序设计基础-常量、变量、标识符

    2 1常量 变量 标识符 2 1 1标识符 定义 标识符就是一个名称 用来表示变量 常量 函数以及文件等名称 格式 合法的标识符由字母 大 小写均可 数字和下划线组成 并且必须以字母或下划线开头 注 1 C语言是一种对大小写敏感的语言 所以
  • postgres格式化时间_在postgresql数据库中判断是否是数字和日期时间格式函数操作...

    在编写GreenPlum函数的过程中 遇到要判断字符串是否是数字和日期格式的情况 基于GreenPlum和postgresql的亲缘关系 找到了下面两个函数 1 判断字符串是否是数字 CREATE OR REPLACE FUNCTION i
  • CVPR2017-目标检测相关

    1 Speed accuracy trade offs for modern convolutional object detectors 其主要考虑三种检测器 Faster RCNN R FCN SSD 作为元结构 三种CNN网络 VGG
  • Python 处理 ini 文件 的模块

    Python 处理 ini 文件 的模块 1 ini 文件 2 configparser 模块 2 1 语法介绍 2 2 操作示例 1 ini 文件 ini 文件是 Initialization File 的缩写 即初始化文件 ini 文件
  • 面向安全数据包分析

    网络安全是一个十分重要的话题 但是它同时也是一个十分复杂的问题 各种针对网络的攻击手段层出不穷 对于网络的守护者来说 将这些手段进行分类是一个十分棘手的工作 网络安全是一个非常复杂的问题 所以我们按照TCP IP分层的方式 对网络中的常见攻
  • 浅谈测试开发岗位

    一 测试开发的概念与需求 测试开发 通常也被称为自动化测试 是一个涵盖了从测试设计 开发 执行和结果分析等一系列活动的职位 在软件开发的生命周期中 测试开发起着至关重要的作用 其主要目标是确保软件的质量和性能达到预期的标准 测试开发工程师通
  • MySQL查看当前数据库视图-SQL语句

    引言 查询语句为 show full tables where table type 可查询当前数据库表 一 创建一个视图 创建视图 create view v stu as 视图内容 连接的一个表 select name from t s
  • Stm32待机模式的进入与唤醒

    1 基础介绍 1 1 单片机的 低功耗模式 像是手机的待机模式 不同于正常运行模式 处于一种省电省资源的状态 1 2 在运行情况下 HCLK为cpu提供时钟 cortex m3内核执行程序的代码 如果处于中断事件的等待时 可以进入低功耗模式
  • 基于R语言分析身高与体重的相关性分析

    本博文源于暨南大学的 多元数据统计分析及R语言建模 旨在讲述身高与体重相关性分析 在概率论与数理统计课程中 两个变量之间协方差的标准化 因此先要熟悉并回忆公式 套用在R语言即可 例子 分析身高 kg 与体重 cm 的相关性 gt x1 c
  • 小心情

    好久没写博客了 总结下现在的自己 还是依旧那么的 情绪控 变化那么快 有时 都受不了自己的 坏脾气 学习再也没像原来的那么卖力 有那么点的小颓废 实验室布置的任务有那么点的小懈怠 一切都没有进展 生活依旧那么平淡 却也没有自己想要的那种安逸
  • linux内核对于指令异常的处理

    1 处理流程 以arm64来介绍一下流程 如果在用户层发生指令异常时 首先进入入口el0 undef arch arm64 kernel entry s el0 undef Undefined instruction enable inte