如何在x86-64架构上使用INVLPG?

mig*_*ymo 2 c x86 assembly x86-64 tlb

我正在尝试测量内存访问时序,并需要降低TLB命中和未命中产生的噪音

为了清除TLB中的特定页面,我尝试使用INVLPG指令,遵循以下两个示例:http://wiki.osdev.org/Paging和 http://wiki.osdev.org/Inline_Assembly/Examples

我写了以下代码:

static inline void __native_flush_tlb_single(unsigned long addr)
{
   asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}
Run Code Online (Sandbox Code Playgroud)

但是生成的二进制文件会在执行时抛出SIGSEGV.在我优先考虑英特尔语法时,我看了一下特定的反汇编:

invlpg BYTE PTR [rdi]
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,将使用RDI中的字节值调用invlpg,但宁可需要QWORD地址.

但是第二个链接说"m指针指向逻辑地址,而不是物理或虚拟地址:ds段的偏移量"

那么INVLPG需要偏离ds段?但是ds64不再用于AMD64,是吗?

有人可以解释我如何使用AMD64的INVLPG指令或如何在这个架构上逐出TLB条目?

mig*_*ymo 5

发生SIGSEGV是因为INVLPG是一个特权指令,只能从内核代码中调用(感谢Cody Gray).

为了演示INVLPG的使用,我写了一点LKM invlpg_mod.c:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/types.h>

// LICENSE
MODULE_LICENSE("GPL");

static inline void invlpg(unsigned long addr) {
    asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}


// init module
static int __init module_load(void) {
    int mem;
    invlpg((unsigned long) &mem);
    printk("Evicted %p from TLB", &mem);
}


//unload modules
static void __exit module_unload(void) {
    printk("Goodbye.");
}

module_init(module_load);
module_exit(module_unload);
Run Code Online (Sandbox Code Playgroud)

确保安装了linux-headers并使用此Makefile构建LKM:

KDIR = /lib/modules/$(shell uname -r)/build
PWD = $(shell pwd)

obj-m = invlpg_mod.o

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    make -C $(KDIR) M=$(PWD) clean
Run Code Online (Sandbox Code Playgroud)

加载LKM:

 sudo insmod invlpg_mod.ko
Run Code Online (Sandbox Code Playgroud)

并卸载它:

sudo rmmod invlpg_mod.ko
Run Code Online (Sandbox Code Playgroud)

看输出:

dmesg | tail
Run Code Online (Sandbox Code Playgroud)