Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use INVLPG on x86-64 architecture?

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?

like image 750
mightymo Avatar asked Jan 24 '26 09:01

mightymo


1 Answers

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
like image 84
mightymo Avatar answered Jan 26 '26 23:01

mightymo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!