Linux Mem -- MTE in AArch64 Linux

目录

1 介绍

2 用户空间支持

3 PROT_MTE内存属性

4 Tag Check Faults

5 排除IRG、ADDG和SUBG等指令产生的tag

6 每个CPU建议的tag check mode

7 初始进程状态


近期在深入了解AArch64 Linux MTE机制,本文是个人对于Linux org学习。原文来自 Memory Tagging Extension (MTE) in AArch64 Linux — The Linux Kernel documentation

1 介绍

        ARMv8.5 版本的处理器介绍了MTE(memory tagging Extensio)特性。MTE是基于ARMv8.0的虚拟地址标签(TBI:top byte ignore)特性 ,允许软件访问4-bit的allocation tag 为16字节粒度物理空间。具有MTE特性的内存空间映射需要带Normal-Tagged内存属性。逻辑tag被应用于虚拟地址的59-56bit。使能MTE的处理器将比较logical tag 和 allocation tag,如果比较失败则根据系统寄存器配置上报响应异常。

2 用户空间支持

        CONFIG_ARM64_MTE使能且硬件支持MTE,内核会通过HWCAP2_MTE向用户空间宣导支持MTE功能。

3 PROT_MTE内存属性

        为了访问allocation tag,用户进程必须为使用tagged内存属性为其地址空间。

        PROT-MTE --- 允许访问Page的MTE allocation tags

        当这些page 首次映射到用户空间且保留 copy-on-write时,其对应的alloation tag被设置为0。支持MAP_SHARED 并且allocation tag 可以在多个进程间共享。

        Note:a. PROT_MTE 仅仅支持匿名映射(MAP_ANONYMOS) 、基于Ram的文件映射(tmpfs、memfd)。传递该属性给其他的映射类型间返回 -EINVAL。

                   b. PROT_MTE不能够通过mprotect清除 

                   c. 具有MADV_DONTNEED 和 MADV_FREE属性的通过madvise()获取的内存可以清除allocation tags。

4 Tag Check Faults

        访问具有PROT_MTE属性的内存区域,当其logical tag 和allocation tag不匹配时,会有三种可配置的行为生发:

         a.忽略 -- 默认配置,CPU将会略 tag check fault。

         b. synchronous -- 内核将同步上报SIGSEGV, si_code = SEGV_MTESERR 和 si_addr = <fault-address>,该次系统访问不能执行。 如果SIGSEGV被违规进程忽略或者阻塞,对应的进程将执行coredump。

         c. Asynchronous -- 在进程违规发生时,内核异步的发出SIGSEGV带有si_code= SEGV_MTEAERR, si_addr = 0的信号。

        用户可以通过prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)系统调用为每个进程选择不同的行为。PR_MTE_TCF_MASK位域,对应的flags值如下:

               PR_MTE_TCF_NONE <--> ignore tag check faults

               PR_MTE_TCF_SYNC  <--> synchronous tag check fault mode

               PR_MTE_TCF_ASYNC <--> asynchronous tag check fault mode

如果没有模式指定,tag check fault将被忽略。如果一个模式被设置,tag check falut发生时则按照该改定模式运行。如果多中模式被设置,那种模式被选择需要看随后的“Per-CPU选择 tag 检测模式“。可以通过prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)系统函数获取当前的tag 检测模式。可以通过MSR TCO, #1指令设置PSTATE.TCO状态位关闭用户进程的tag check功能。

注意:a.不用考虑中断上下文,当PSTATE.TCO=0时信号处理程序总是被执行。TCO状态在sigreturn()过程恢复。

          b.不可能匹配所有的逻辑tag为用户应用 ??

          c.如果用户线程标记检查模式为PR_MTE_TCF_NONE或PR_MTE_TCF_ASYNC,则不检查内核访问用户地址空间。(例如,读取()系统调用)。如果标记检查模式为PR_MTE_TCF_SYNC,内核会尽最大努力检查其访问的用户地址,但它不能总是保证它。内核访问用户空间总视PSTATE.TCO值为零,无论用户配置如何。

5 排除IRG、ADDG和SUBG等指令产生的tag

        架构允许通过设置GCR_EL1.Exclude寄存器位域来排除某些随机产生的tag。默认情况,Linux排除所有的非零tag。用户进程可以通过prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)系统函数指定特定的tag值,flag中包含了以PR_MTE_TAG_MASK为掩码的tag位域。

        注意:GCR_EL1寄存器提供的排除tag的掩码,而prctl函数提供的是包含tag的掩码。

6 每个CPU建议的tag check mode

        一些CPU在MTE严格tag check 模式下的性能和非严格tag check检模式下的性能是相似的,当非严格检测模式请求时这些CPU可以使用为严格tag check模式,这样即利于错误检测又没有太多性能下降。为了支持这种情况,特权用户可以将严格检测模式做为CPU的首选检测模式。

        每个CPU的首选检测模式可以过/sys/devices/system/cpu/cpu<N>/mte_tcf_preferred控制,特权用户可以向该路径写入async 或者sync值。默认每个CPU的首选模式为async。

        为了允许程序可能在CPU的首选标记检查模式下运行,用户程序可以设置多个tag check fault模式到prctl()的flag参数。如果CPU的首选模式是要设置的tag check模式的task检测子集,CPU的首先模式可能被选择。否则,将设置为task要设置的任一模式。

7 初始进程状态

        execve()执行时,新进程将有如下配置:

                a. PR_TAGGED_ADDR_ENABLE设置为0,即diable tag 

                b.Tag check fault被忽略

                c.PSTATE.TC0设置为0 ,即disable tag check

                d.初始映射的内存没有PROT_MTE属性

        在fork()上,新进程继承父进程的配置和内存映射属性。除了使用MADV_WIPEONFORK的monust()范围,它将清除数据和标记。

<think>好的,我需要帮助用户了解如何正确使用qemu-aarch64命令。用户之前已经询问过关于qemu-arm的使用,现在转向qemu-aarch64,可能是在尝试运行64位ARM系统。首先,我需要区分qemu-system-aarch64和qemu-aarch64的不同。 根据用户提供的引用[1],用户可能看到了在Windows上创建aarch64虚拟机的示例,但用户现在可能更关注的是在Linux环境下使用qemu-aarch64运行用户模式程序或全系统模拟。需要明确qemu-aarch64通常指的是用户模式模拟,而qemu-system-aarch64是系统模式模拟,两者的用途不同。 用户之前的问题中,我详细讲解了qemu-arm的使用,包括运行静态和动态程序、调试等。现在需要将类似的内容迁移到aarch64架构,同时考虑64位特有的参数和配置。比如,动态链接库路径可能不同,CPU型号也需要对应,如cortex-a72、cortex-a53等。 需要检查用户是否可能混淆了用户模式和系统模式。在回答中应该明确区分这两种模式的使用场景。用户提供的引用中提到的命令是系统模式,但用户的问题可能更倾向于用户模式,所以需要确认用户的实际需求。 接下来,我需要构建一个结构清晰的指南,包括核心命令结构、安装验证、典型场景示例、常见问题等。同时,要确保使用正确的参数,比如-L路径在aarch64下可能不同,例如/usr/aarch64-linux-gnu。还需要提供编译示例,使用aarch64-linux-gnu-gcc编译器。 另外,用户可能遇到动态链接库的问题,需要指导如何正确设置库路径或安装对应的交叉编译库。在调试部分,可能需要使用gdb-multiarch连接到qemu的调试端口,这与之前qemu-arm的步骤类似,但需确认端口和架构是否正确。 在系统模式部分,用户引用中的参数可以作为示例,但需要解释每个参数的作用,如-M指定机器类型,-bios指定固件,-device添加外设等。同时,要提醒用户需要准备合适的EFI固件和镜像文件,比如UEFI.fd和安装ISO。 还要考虑用户的环境,是否已经安装了必要的包,比如qemu-system-arm、交叉编译工具链等。对于不同发行版,安装命令可能不同,需要给出示例,如Ubuntu下的安装步骤。 最后,生成相关问题,帮助用户进一步探索,比如如何配置网络、性能优化、与用户模式的区别等。确保引用正确,比如用户提供的引用[1]是关于系统模式的,可能在相关问题中提及。 需要检查所有命令的正确性,避免拼写错误,并确保参数适用于aarch64架构。同时,保持回答结构清晰,步骤详细,便于用户逐步操作验证。</think>### QEMU-aarch64 使用详解(用户模式 + 系统模式) --- #### 一、核心模式区分 1. **用户模式**:`qemu-aarch64`(直接运行ARM64程序) ```bash # 运行ARM64程序(类似qemu-arm的64位版本) qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello_aarch64 ``` 2. **全系统模式**:`qemu-system-aarch64`(完整虚拟机) ```bash # 启动ARM64虚拟机(需搭配UEFI固件) qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd -hda ubuntu-arm64.img ``` --- #### 二、用户模式实战(运行单程序) **步骤1:环境准备** ```bash # Ubuntu/Debian安装依赖 sudo apt install qemu-user-static gcc-aarch64-linux-gnu # 验证工具链 aarch64-linux-gnu-gcc --version # 应显示aarch64编译器信息[^2] ``` **步骤2:编译与运行** ```c // hello.c #include <stdio.h> int main() { printf("ARM64程序运行成功\n"); return 0; } ``` ```bash # 编译ARM64程序 aarch64-linux-gnu-gcc -static hello.c -o hello_static aarch64-linux-gnu-gcc hello.c -o hello_dynamic # 运行动态链接程序(需指定库路径) qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./hello_dynamic # 输出"ARM64程序运行成功"即验证通过[^3] ``` **调试技巧**: ```bash # 启动GDB调试 qemu-aarch64 -g 1234 ./hello_dynamic & gdb-multiarch ./hello_dynamic (gdb) target remote :1234 (gdb) b main ``` --- #### 三、全系统模式配置(完整虚拟机) **核心参数说明**: ```bash qemu-system-aarch64 \ -M virt \ # 使用QEMU虚拟化平台 -cpu cortex-a72 \ # 指定CPU型号 -smp 4 \ # 4个CPU核心 -m 8G \ # 内存大小 -bios QEMU_EFI.fd \ # UEFI固件(需提前准备) -drive file=ubuntu-arm64.img,format=raw \ # 系统磁盘 -device virtio-gpu-pci \ # GPU加速 -netdev user,id=net0 -device virtio-net-pci,netdev=net0 # 网络配置 ``` **典型启动流程**: 1. 下载UEFI固件: ```bash wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd ``` 2. 创建虚拟磁盘: ```bash qemu-img create -f qcow2 ubuntu-arm64.img 20G ``` 3. 启动安装镜像: ```bash qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G \ -bios QEMU_EFI.fd -cdrom ubuntu-22.04-live-server-arm64.iso \ -drive file=ubuntu-arm64.img,format=qcow2 \ -device virtio-net-device,netdev=net0 -netdev user,id=net0 ``` --- #### 四、常见问题解决 | 问题场景 | 解决方案 | |---------|----------| | **UEFI固件缺失** | 安装`qemu-efi-aarch64`包或手动下载`QEMU_EFI.fd` | | **启动卡在UEFI Shell** | 在Shell中执行`FS0:\EFI\BOOT\BOOTAA64.EFI`[^1] | | **动态链接库错误** | 使用`-L`指定路径或安装`libc6-arm64-cross` | | **网络不可用** | 添加`-nic user,model=virtio-net-pci`参数 | | **图形界面黑屏** | 改用`-nographic`或添加`-device virtio-gpu-pci` | --- #### 五、性能优化建议 1. **启用KVM加速**(需宿主CPU支持): ```bash qemu-system-aarch64 -enable-kvm -machine virt,gic-version=3 ... ``` 2. **使用virtio设备**: ```bash -drive file=disk.img,if=virtio -netdev user,id=net0,model=virtio ``` 3. **分配大页内存**: ```bash -mem-prealloc -mem-path /dev/hugepages ``` --- ### 验证成功标志 1. 用户模式程序正确输出预期结果 2. 全系统模式下完成操作系统安装 3. 虚拟机内执行`uname -m`显示`aarch64` 4. GDB可正常调试ARM64汇编指令 --- ### 高级应用示例 **运行Android ARM64镜像**: ```bash qemu-system-aarch64 -M virt -cpu cortex-a72 -m 6G \ -bios QEMU_EFI.fd -device virtio-gpu-pci \ -drive file=android-arm64.img,format=raw \ -nic user,hostfwd=tcp::5555-:5555 # 启用ADB端口转发 ``` **交叉编译内核测试**: ```bash # 编译ARM64内核 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 # 使用QEMU启动测试 qemu-system-aarch64 -M virt -cpu cortex-a72 -m 2G \ -kernel arch/arm64/boot/Image -append "root=/dev/vda console=ttyAMA0" ``` --- ### 相关问题 1. 如何通过QEMU实现ARM64与x86主机之间的文件共享? 2. 用户模式与系统模式在资源占用上有何本质区别? 3. 如何配置TPM安全芯片支持运行Windows ARM64? 4. QEMU中如何调试ARM64内核的启动过程? : UEFI固件路径可能因发行版不同而变化 [^2]: 交叉编译工具链需与目标系统glibc版本匹配 [^3]: `qemu-aarch64-static`更适合容器环境嵌入使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值