问题
I'm trying to measure memory access timings and need to reduce the noise produced by TLB hits and misses
In order to clear a specific page out of the TLB I tried to use the INVLPG instruction, following those two examples: http://wiki.osdev.org/Paging and http://wiki.osdev.org/Inline_Assembly/Examples
I wrote the following code:
static inline void __native_flush_tlb_single(unsigned long addr)
{
asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}
But the resulting binary throws an SIGSEGV on execution. As I prefere Intel syntax, I had a look at the particular disassembly:
invlpg BYTE PTR [rdi]
If I understand this correctly, invlpg will be called with the byte value at RDI, but would rather require a QWORD address.
However the second link says "The m pointer points to a logical address, not a physical or virtual one: an offset for your ds segment"
So INVLPG needs an offset from the ds segment? But the ds segment isn't used in AMD64 anymore, is it?
Can someone explain me how to use the INVLPG instruction with AMD64 or how to evict an TLB entry on this architecture?
回答1:
The SIGSEGV happens because INVLPG is a privileged instruction and can only be called out of kernel code (Thanks Cody Gray).
In order to demonstrate the use of INVLPG I wrote a little 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);
Make sure you have the linux-headers installed and build the LKM with this Makefile:
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
Load the LKM with:
sudo insmod invlpg_mod.ko
And unload it:
sudo rmmod invlpg_mod.ko
See the output:
dmesg | tail
来源:https://stackoverflow.com/questions/37752664/how-to-use-invlpg-on-x86-64-architecture