Как установить / снять флажок TF на процессоре Intel x86 IA32 в пользовательском режиме

Я хотел бы знать шаги для установки / очистки EFLAGS.TF в пользовательском режиме на x86 IA32 Intel CPU

попробовал ниже для очистки флага TF, но получаю ошибку ***** Unhandled interrupt vector *****

__asm__ volatile("pushl %eax\n\t"
                        "pushfl\n\t"
                        "popl %eax\n\t"
                        "xorl $0x0100, %eax\n\t"
                        "pushl %eax\n\t"
                        "popfl\n\t"
                        "popl %eax\n\t");

2 ответа

XOR слегка переворачивается вместо того, чтобы всегда очищать его. И это одна опция, BTR (бит-тест-сброс) это другая. BTR с назначением памяти действительно медленный с источником регистра, но это совсем не плохо с немедленным (только 2 мопа на Haswell, 3 на Skylake. Однако до 4 на AMD, где он стоит 2 мопа даже для btr $9, %eax.)

popf довольно медленный (9 моп, 1 на 20 циклов на Скайлэйке). Или на Ryzen, 35 мопов и один на 13 циклов. ( http://agner.org/optimize). Поэтому оптимизация окружающего кода не будет иметь большого значения, но интересно найти способ сохранить компактность размера кода.

Вам не нужно сохранять / восстанавливать EAX самостоятельно, просто скажите компилятору, что вы хотите его затереть : "eax" в качестве списка clobber, или используйте фиктивный операнд вывода (обратите внимание, что я использую расширенный asm GNU C, а не basic).

static inline
void clear_tf(void) {
    long dummy;       // there's no type that's always 32-bit on 32-bit, and always 64 on 64-bit.  x32 uses 32-bit pointers in long mode so uintptr_t or size_t doesn't work.
   // if porting to x86-64 System V user-space: beware that push clobbers the red-zone
    __asm__ volatile("pushf \n\t"
                     "pop   %[tmp] \n\t"
                     "btr   $9, %[tmp]\n\t"   // reset bit 9
                     "push  %[tmp] \n\t"
                     "popf"
                    : [tmp] "=r"(dummy)
                    : // no inputs
                    : // no clobbers.  // "memory" // would block reordering with loads/stores.
                );
}

Или просто не трогайте никакие регистры: это тоже очень эффективно, особенно на AMD Ryzen, где нет стеков с синхронизацией стека, а в качестве места назначения памяти AND используется однократная операция.

static inline
void clear_tf(void) {
   // if porting to x86-64 System V user-space: beware that push clobbers the red-zone
    __asm__ volatile("pushf \n\t"
                     "andl $0xFFFFFEFF, (%esp) \n\t"  // 1 byte larger than the pop/btr/push version
                     "popf"
                );
    // Basic asm syntax: no clobbers.
}

Для меньшего размера кода, btrl $9, (%esp) наверное хорошо. Все еще только 2 мопа на Haswell (3 на Skylake), но на 2 байта меньше, чем andl, andb $0xfe, 1(%esp) также имеет тот же размер, но вызывает остановку пересылки магазина и составляет 2 мопа + макс стека синхронизации при использовании после push, pop %%eax; and $0xfe, %ah; push %eax также имеет такой же размер, а также 3 мопа (плюс моп с частичным регистром, который выдает в цикле сам по себе на Haswell / SKL). Но это приятно на AMD.


портативность

Кстати, в коде пространства пользователя x86-64 System V вы не можете безопасно нажимать / выталкивать, не заглушая красную зону компилятора, так что вы, вероятно, захотите add $-128, %rsp до pushи восстановить его после.

В коде ядра нет красной зоны, так что push/pop внутри встроенного asm отлично.

Windows использует другой ABI без красной зоны.

С кодом ниже он работал нормально. Спасибо

  __asm__ volatile("pushl %eax;\
                    pushfl;\
                    popl %eax;\
                    andl $0xFFFFFEFF, %eax;\
                    pushl %eax;\
                    popfl;\
                    popl %eax;"
                    );
Другие вопросы по тегам