增加对ARM64和X86的硬件预取控制驱动的支持

该博客介绍了为ARM64和X86平台添加的sysfs接口,用于用户态控制CPU硬件预取行为,以进行性能调优。此驱动创建了通用和架构特定的部分,允许在每个CPU的cache/index目录下通过属性文件调整预取控制。文中还给出了X86平台上的使用示例,并提到了存在的问题,如在某些情况下'lscpu'命令可能失败。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         这组PATCH增加了sysfs接口来控制CPU硬件预取行为对ARM64和X86进行用户态的性能调优。

1 背景

        A64FX和一些intel处理器有依赖于实现的寄存器来控制CPU硬件预取行为。A64FX有IMP_PF_STREAM_DETECT_CTRL_EL0,intel处理器有MSR_MISC_FEATURE_CONTROL。这些寄存器不能从用户态访问。

        使用这个的优点为改善性能。作为一个性能优化的例子,运行Stream benchmark在A64FX被描述。

        对于MSR 0x1a4,通过MSR驱动也可以从用户态修改该值。但是不建议使用MSR驱动,因此它需要一个合适的内核接口。

        因为这些原因,我们需要一个新的合适内核接口来控制IMP_PF_STREAM_DETECT_CTRL_EL0和MSR 0x1a4。

2 总体设计

        驱动的源码分为通用部分(driver/base/pfctl.c)和架构部分(arch/xxx/pfctl.c)。通用部分描述为不依赖于架构的处理,比如创建sysfs。架构部分被描述为依赖于架构的处理。它必须至少包含支持哪种硬件预取单元以及如何对寄存器进行读和写。这些信息通过通用部分的注册函数被设置。

        如果CPU支持硬件预取控制行为,驱动在每个CPU的cache/index目录下创建”prefetch_control”目录和一些属性文件。每个属性文件与父index目录的cache级别相关。

        Sysfs接口的细节描述在文件Documentation/ABI/testing/sysfs-devices-system-cpu。

        该驱动需要cache sysfs目录和cache level/type信息。在ARM处理器中,这些信息可以从寄存器中获取,而不需要从ACPI PPTT获取。

        如果机器不支持ACPI PPTT和Kconfig,且支持硬件预取控制,我们可以增加处理来使用寄存器来创建cache/index目录。

        这行为会造成一个问题,将在后面描述。

3 例子

        本部分提供了一个在X86 INTEL_FAM6_BROADWELL_X上使用sysfs接口的例子。

        这个模式有如下寄存器说明:

  1. L2硬件预取禁用
  2. L2相邻cache line预取禁用
  3. DCU硬件预取禁用
  4. DCU IP预取禁用

        [63:4] 保留

        在这个例子中,index0(L1D cache)与bit[2,3]相关,index2(L2 cache)与bit[0,1]相关。在CPU1的index0和index2的属性文件如下所示:

#ls /sys/devices/system/cpu/cpu1/cache/index0/prefetch_contol

Hardware_prefetcher_enable

Ip_prefetcher_enable

#ls /sys/devices/system/cpu/cpu1/cache/index2/prefetch_contol

Adjacent_cache_line_prefetcher_enable

Hardware_prefetcher_enable

        如果用户想要禁用CPU1的L2相邻cache line,操作如下:

#echo 0 > /sys/devices/system/cpu/cpu1/cache/index2/prefetch_contol/Adjacent_cache_line_prefetcher_enable

        在其他例子中,A64FX的index0如下所示:

#ls /sys/devices/system/cpu/cpu1/cache/index0/prefetch_control/

Stream_detect_prefetcher_dist

Stream_detect_prefetcher_enable

Stream_detect_prefetcher_strong

4 已知的问题

        “lscpu”命令会以-ENOENT结束因为目录cache/index存在但shared_cpu_map文件不存在。这是因为patch 5,它创建了cache/index目录包含level和type,但没有ACPI PPTT。

LKML: Kohei Tarumizu: [PATCH v2 0/8] Add hardware prefetch control driver for arm64 and x86

<think>嗯,用户之前让我介绍了中断向量表异常向量表,现在他们又问了“只针对ARM的Linux说”。我需要先理解他们的需求。可能他们想更深入地了解在ARM架构的Linux系统中,中断异常是如何处理的,特别是与之前提到的向量表相关的内容。 首先,我应该回顾一下之前的内容,在ARM架构中,异常向量表是独立的,地址在0x00000000或0xFFFF0000。而x86中使用的是IDT。现在用户希望聚焦于ARM的Linux实现,可能需要详细说明Linux内核在ARM上是如何处理中断异常的。 接下来,需要确定用户可能关心的点。比如,ARM Linux中的异常向量表结构、中断处理流程、设备树(Device Tree)的作用,以及软件中断(SWI)或系统调用的处理方式。此外,可能还涉及上下文切换、中断控制器(如GIC)的集成,以及一些实际例子如GPIO中断的处理流程。 同时,用户可能对ARM的不同模式(如IRQ模式、SVC模式)在Linux中的使用感兴趣,或者如何从异常向量跳转到C语言的处理函数。此外,可能需要区分旧版本的Linux内核(如使用__vectors_start)新版本(如使用VBAR)的变化。 需要注意的是,用户可能有一定的技术背景,但可能需要避免过于晦涩的细节,而侧重于整体流程关键组件。需要确认是否要包含代码示例或图表,但根据之前的回答,用户似乎接受代码片段,所以可以考虑加入一些关键代码结构,如异常向量表的定义或中断处理函数的注册。 还要考虑用户可能的误区,比如是否所有的异常都由内核处理,或者用户空间程序如何处理信号(如SIGSEGV)与内核异常处理的关系。此外,可能涉及ARM Linux中的一些特定机制,如FIQ的使用情况,或者多核处理中的中断分发。 最后,需要组织信息,使其结构清晰,分点说明,帮助用户逐步理解ARM Linux中的中断异常处理机制,同时与之前的内容对比,突出ARM架构下的特殊性。</think>### **ARM 架构下的 Linux 中断与异常处理** 在 ARM 架构的 Linux 系统中,**中断****异常**的处理机制紧密结合硬件特性与操作系统内核设计,以下是针对 ARM-Linux 的核心实现细节: --- ### **1. ARM 异常向量表与 Linux 内核的适配** #### **硬件基础** - **ARM 异常向量表**: ARM 架构定义了 **7 种异常类型**,每个异常对应固定的内存地址(称为异常向量): | **地址** | **异常类型** | **Linux 处理逻辑** | |-------------------|----------------------------|----------------------------------------| | `0x00000000` | 复位(Reset) | 系统启动时由 Bootloader 处理 | | `0x00000004` | 未定义指令(Undefined Instruction) | 触发 SIGILL 信号,终止或调试用户进程 | | `0x00000008` | 软件中断(SWI,系统调用) | 用户态到内核态的切换入口(如 `svc` 指令) | | `0x0000000C` | 中止(Prefetch Abort) | 指令错误,通常由内存访问权限引发 | | `0x00000010` | 数据中止(Data Abort) | 数据访问错误(如缺页异常) | | `0x00000014` | 保留 | 未使用 | | `0x00000018` | IRQ 中断 | 硬件外设中断(如定时器、网络卡) | | `0x0000001C` | FIQ 快速中断 | Linux 默认未启用(需特定配置) | - **高地址向量表**(可选): ARM 支持将异常向量表重定位到 `0xFFFF0000`,Linux 内核通常使用此特性,以避免低地址内存冲突。 #### **Linux 内核的实现** - **异常向量表初始化**: 内核启动时通过 `__vectors_start` 符号定义异常处理入口,每个异常向量指向一段**汇编代码**,用于快速保存上下文并跳转到 C 语言处理函数。 示例(简化版汇编逻辑): ```asm __vectors_start: ldr pc, [pc, #0x18] @ Reset (未实际使用,由 Bootloader 处理) ldr pc, [pc, #0x18] @ Undefined Instruction ldr pc, [pc, #0x18] @ SWI (系统调用) ldr pc, [pc, #0x18] @ Prefetch Abort ldr pc, [pc, #0x18] @ Data Abort ldr pc, [pc, #0x18] @ Reserved ldr pc, [pc, #0x18] @ IRQ ldr pc, [pc, #0x18] @ FIQ ``` - **向量表重定位**: 内核通过设置 **VBAR(Vector Base Address Register)** 将异常向量表重定位到内核虚拟地址空间(如 `0xFFFF0000`)。 --- ### **2. 中断处理流程(以 IRQ 为例)** #### **硬件触发阶段** 1. **中断触发**: 外设(如 GPIO、定时器)通过中断控制器(如 **GIC, Generic Interrupt Controller**)向 CPU 发送中断信号。 2. **中断优先级仲裁**: GIC 根据中断优先级状态,将最高优先级的中断传递给 CPU。 #### **内核响应阶段** 1. **异常向量跳转**: CPU 进入 **IRQ 模式**,从 `0x00000018` 或 `0xFFFF0018` 加载指令,跳转到 `irq_handler` 汇编入口。 2. **上下文保存**: - 保存被打断程序的寄存器(`r0-r12`, `lr`, `spsr`)到内核栈。 - 切换到 **SVC 模式**(内核特权模式)。 3. **中断处理分发**: - 调用 `asm_do_IRQ()` 函数,读 GIC 的 **IAR(Interrupt Acknowledge Register)** 获中断号。 - 根据中断号查找对应的 **中断处理函数**(由驱动注册)。 #### **中断处理示例:GPIO 按键中断** ```c // 驱动注册中断处理函数 request_irq(IRQ_GPIO_BUTTON, button_handler, IRQF_TRIGGER_FALLING, "gpio_button", NULL); // 中断处理函数 static irqreturn_t button_handler(int irq, void *dev_id) { printk("Button pressed!\n"); return IRQ_HANDLED; } ``` --- ### **3. 异常处理:以缺页异常(Data Abort)为例** 1. **触发条件**: 用户程序访问未映射的虚拟地址或权限不足的内存。 2. **内核处理流程**: - CPU 跳转到 `data_abort` 异常向量,保存上下文并调用 `do_DataAbort()` 函数。 - 内核解析异常原因: - 若因**缺页**触发,调用 `handle_mm_fault()` 分配物理页,更新页表。 - 若因非法访问(如空指针),向用户进程发送 `SIGSEGV` 信号终止进程。 --- ### **4. 系统调用(SWI/SVC 异常)** - **用户态到内核态切换**: 用户程序通过 `svc` 指令触发 SWI 异常,跳转到 `vector_swi` 处理。 ```asm ; 用户态调用 write() 系统调用示例 mov r7, #4 @ 系统调用号(sys_write) mov r0, #1 @ 文件描述符(stdout) ldr r1, =msg mov r2, #len svc 0 @ 触发 SWI 异常 ``` - **内核分发系统调用**: `vector_swi` 根据系统调用号(`r7` 寄存器)从 `sys_call_table` 找到对应内核函数(如 `sys_write`)。 --- ### **5. Linux 对 ARM 中断控制器的支持** - **GIC(Generic Interrupt Controller)**: Linux 内核通过 **GIC 驱动**管理中断,支持多核中断分发、优先级抢占中断屏蔽。 - **关键操作**: - `gic_handle_irq()`:处理中断入口。 - `gic_mask_irq()` / `gic_unmask_irq()`:屏蔽或启用中断。 - **设备树(Device Tree)配置**: 外设中断信息在设备树中定义,内核启动时解析。 示例: ```dts // 定义 UART 中断 uart0: serial@101f1000 { compatible = "arm,pl011"; reg = <0x101f1000 0x1000>; interrupts = <1 0>; // SPI 中断号 1,高电平触发 }; ``` --- ### **6. 实际调试与工具** - **查看中断统计**: ```bash cat /proc/interrupts ``` 输出示例: ``` IRQ CPU0 CPU1 1 100 0 GIC uart0 2 50 30 GIC eth0 ``` - **动态追踪异常**: 使用 `perf` 工具监控缺页异常: ```bash perf stat -e exceptions:page_faults_user ./my_program ``` --- ### **总结:ARM-Linux 的关键设计** 1. **异常向量表重定位**:通过 VBAR 将向量表映射到内核地址空间。 2. **中断分层处理**:硬件响应 → 上下文保存 → 中断分发 → 驱动处理。 3. **缺页异常与虚拟内存**:动态分配物理页,支持按需分页(Demand Paging)。 4. **系统调用路径**:通过 SWI/SVC 异常实现用户态与内核态切换。 5. **中断控制器抽象**:GIC 驱动屏蔽硬件差异,提供统一中断管理接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值