Так, вони вимагають машинного коду та всіх операндів пам'яті.
Чи не повинен ЦП отримувати доступ до сторінок пам'яті послідовно, тобто спочатку прочитайте інструкцію, а потім отримайте доступ до операнду пам'яті?
Так, це логічно те, що відбувається, але виняток помилок сторінки перериває цей двоступеневий процес і відкидає будь-який прогрес. Процесор не може згадати, яка інструкція була в середині, коли сталася помилка сторінки.
Коли обробник помилок сторінки повертається після обробки дійсної помилки сторінки, RIP = адреса інструкції про несправності, тому процесор повторно виконує її з нуля .
Було б законно, щоб ОС модифікувала машинний код несправної інструкції і очікувала, що вона виконає іншу інструкцію після того, як стоїть iret
обробник сторінки-помилки (або будь-який інший виняток або обробник переривання). Тому AFAIK архітектурно вимагає, щоб процесор повторно вибирав код з CS: RIP у випадку, про який ви говорите. (Якщо припустити, що він навіть повертається до несправного CS: RIP, а не планує інший процес під час очікування диска з помилкою жорсткої сторінки або доставки SIGSEGV до обробника сигналу з недійсної помилки сторінки.)
Можливо, це також архітектурно потрібно для входу / виходу гіпервізора. І навіть якщо це прямо не заборонено на папері, це не так, як працюють процесори.
@torek зауважує, що деякі (CISC) мікропроцесори частково декодують інструкції та скидають стан мікрорегістру на помилку сторінки , але x86 - це не так.
Кілька інструкцій є переривчими і можуть зробити частковий прогрес, як-от rep movs
(memcpy in can) та інші строкові інструкції, або зібрати вантажі / розкидати магазини. Але єдиним механізмом є оновлення архітектурних регістрів, таких як RCX / RSI / RDI для рядків ops, або регістри призначення та маски для зборів (наприклад, посібник для AVX2vpgatherdd
). Якщо збереження опкоду / декодування призводить до деякого прихованого внутрішнього реєстру та його перезавантаження після iret від сторінки обробки помилок. Це інструкції, які роблять кілька окремих доступу до даних.
Також майте на увазі, що x86 (як і більшість ISA) гарантує, що інструкції є атомними wrt. переривання / винятки: вони або повністю відбуваються, або взагалі не трапляються до переривання. Переривання інструкції по збірці під час роботи . Так, наприклад add [mem], reg
, потрібно буде скинути навантаження, якщо складова частина виникла, навіть без lock
префікса.
Найгірше число присутніх гостьових просторів користувальницьких сторінок, щоб досягти прогресу, може бути 6 (плюс окремі підрядки таблиці гостьового ядра для кожної з них):
movsq
або movsw
2-байтна інструкція, що охоплює межу сторінки, тому обидві сторінки потрібні для її розшифровки.
- qword source операнд
[rsi]
також розділення сторінки
- qword призначення операнд
[rdi]
також розділення сторінки
Якщо будь-яка з цих 6 сторінок помилка, ми повернемося до прямої.
rep movsd
це також 2-байтна інструкція, і прогрес на одному кроці з неї матиме ту саму вимогу. Подібні випадки на зразок push [mem]
або pop [mem]
можуть бути сконструйовані з нерівним стеком.
Однією з причин (або побічних переваг) для / виготовлення накопичувальних вантажів / розкидання сховищ «переривчастим» (оновлення вектора масок з їх прогресом) є уникнення збільшення цього мінімального сліду для виконання однієї інструкції. Також для підвищення ефективності поводження з декількома несправностями під час одного збору або розсіювання.
@Brandon в коментарях зазначає, що гостю знадобляться таблиці сторінок у пам'яті , а розділення сторінки в просторі користувачів також можуть бути розбиттями 1GiB, тому дві сторони знаходяться в різних під деревах верхнього рівня PML4. Для того, щоб досягти прогресу, HW-сторінка повинна торкатися всіх цих сторінок гостьової таблиці. Ситуація, така патологічна, навряд чи трапиться випадково.
TLB (і внутрішні пристрої прогулянок сторінок ) дозволяють кешувати деякі дані таблиці сторінок, і не потрібно перезапускати прогулянку сторінки з нуля, якщо ОС не зробила invlpg
або встановила новий каталог сторінок верхнього рівня CR3. Жодне з них не є необхідним при зміні сторінки з неприсутньої на теперішню; x86 на папері гарантує, що він не потрібен (тому "негативне кешування" відсутніх PTE заборонено, принаймні не видно програмному забезпеченню). Таким чином, процесор може не VMexit, навіть якщо деякі сторінки гостьових фізичних сторінок таблиці фактично відсутні.
Лічильники продуктивності PMU можуть бути включені та налаштовані таким чином, що інструкція також потребує події perf для запису в буфер PEBS для цієї інструкції. Маска лічильника, налаштована на врахування лише інструкцій з простору користувача, а не в ядро, цілком може бути, що він намагається переповнювати лічильник і зберігати зразок у буфері кожного разу, коли ви повертаєтесь у простір користувачів, створюючи помилку сторінки.