Как использовать INVLPG на архитектуре x86-64?

Я пытаюсь измерить время доступа к памяти и нужно уменьшить шум, производимый попаданиями и пропусками 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");
}

Но полученный бинарный файл генерирует SIGSEGV при выполнении. Поскольку я предпочитаю синтаксис Intel, я посмотрел на конкретную разборку:

invlpg BYTE PTR [rdi]

Если я правильно понимаю, invlpg будет вызываться со значением байта в RDI, но для этого потребуется адрес QWORD.

Однако вторая ссылка говорит: "Указатель m указывает на логический адрес, а не на физический или виртуальный: смещение для вашего сегмента ds"

Таким образом, INVLPG нужно смещение от сегмента DS? Но сегмент ds больше не используется в AMD64?

Может кто-нибудь объяснить мне, как использовать инструкцию INVLPG с AMD64 или как исключить запись TLB в этой архитектуре?

1 ответ

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);

Убедитесь, что у вас установлены linux-headers и соберите LKM с помощью этого 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

Загрузите LKM с:

 sudo insmod invlpg_mod.ko

И выгрузить его:

sudo rmmod invlpg_mod.ko

Смотрите вывод:

dmesg | tail
Другие вопросы по тегам