예, 머신 코드와 모든 메모리 피연산자가 필요합니다.
CPU가 순차적으로 메모리 페이지에 액세스해서는 안됩니다. 즉, 먼저 명령어를 읽은 다음 메모리 피연산자에 액세스해야합니까?
그렇습니다. 논리적으로 일어나는 일이지만 페이지 오류 예외는 해당 2 단계 프로세스를 중단하고 진행 상황을 버립니다. CPU는 페이지 결함이 발생했을 때 어떤 명령이 있었는지 기억할 방법이 없습니다.
유효한 페이지 결함을 처리 한 후 페이지 결함 핸들러가 리턴되면 RIP = 결함 명령의 주소이므로 CPU 는 처음부터 실행을 재 시도합니다 .
OS가 결함 명령의 기계 코드를 수정 iret
하고 페이지 결함 핸들러 (또는 기타 예외 또는 인터럽트 핸들러) 이후에 다른 명령을 실행하는 것이 합법적입니다 . 따라서 AFAIK는 CPU가 CS : RIP에서 코드 페치를 다시 실행해야한다는 것을 아키텍처 적으로 요구합니다. (하드 페이지 결함 디스크를 기다리거나 잘못된 페이지 결함의 신호 처리기에 SIGSEGV를 전달하는 동안 다른 프로세스를 예약하는 대신 결함이있는 CS : RIP로 돌아가는 것으로 가정합니다.)
하이퍼 바이저 입력 / 종료에도 아키텍처 상 필요합니다. 종이에 명시 적으로 금지되어 있지 않더라도 CPU 작동 방식이 아닙니다.
@torek 씨는 일부 (CISC) 마이크로 프로세서가 부분적으로 명령어를 해독하고 페이지 결함 에서 마이크로 레지스터 상태를 덤프 하지만 x86은 그렇지 않다고 말합니다.
일부 명령어는 인터럽트 가능하며 (can의 rep movs
memcpy) 및 기타 문자열 명령어와 같은 부분 진행을 수행 하거나로드 / 스 캐터 저장소를 수집 할 수 있습니다. 그러나 유일한 메커니즘은 문자열 연산을위한 RCX / RSI / RDI 또는 수집을위한 대상 및 마스크 레지스터 (예 : AVX2vpgatherdd
수동 ) 와 같은 아키텍처 레지스터를 업데이트하는 것 입니다. opcode / 디코딩을 유지하지 않으면 일부 숨겨진 내부 레지스터가 생성되고 페이지 결함 핸들러에서 iret 후에 다시 시작됩니다. 이들은 여러 개의 개별 데이터 액세스를 수행하는 명령입니다.
또한 x86 (대부분의 ISA와 마찬가지로)은 명령어가 원자 성임을 보증합니다. 인터럽트 / 예외 : 인터럽트 전에 완전히 발생하거나 전혀 발생하지 않습니다. 작동하는 동안 어셈블리 명령을 중단합니다 . 따라서 예를 들어 접두사가 add [mem], reg
없는 경우에도 상점 부품에 결함이있는 경우로드를 폐기해야 lock
합니다.
앞으로 진행하기 위해 존재하는 최악의 게스트 사용자 공간 페이지 수는 6 개 (각각 별도의 게스트 커널 페이지 테이블 하위 트리)가 될 수 있습니다.
movsq
또는 movsw
페이지 경계에 걸쳐있는 2 바이트 명령어이므로 두 페이지를 모두 해독해야합니다.
- qword 소스 피연산자
[rsi]
도 페이지 분할
- qword 대상 피연산자
[rdi]
도 페이지 분할
이 6 페이지 중 하나라도 오류가 발생하면 다시 정사각형으로 돌아갑니다.
rep movsd
또한 2 바이트 명령어이므로 한 단계 씩 진행해도 동일한 요구 사항이 적용됩니다. 잘못 정렬 된 스택과 같 push [mem]
거나 이와 유사한 경우가 pop [mem]
있을 수 있습니다.
수집로드 / 스 캐터 저장소를 "인터럽트 가능"하게 만드는 이유 (또는 부수적 인 이점 중 하나) (마스크 벡터를 진행 상태로 업데이트)는 단일 명령을 실행하기 위해이 최소 풋 프린트를 늘리지 않기위한 것입니다. 또한 한 번의 수집 또는 분산 중에 여러 결함을 처리하는 효율성을 향상시킵니다.
@Brandon 은 게스트가 메모리에 페이지 테이블이 필요하고 사용자 공간 페이지 분할도 1GiB 분할이 될 수 있다고 언급하면서 두 측면이 최상위 PML4의 다른 하위 트리에 있다고 지적했다. HW 페이지 워크는 모든 게스트 페이지 테이블 페이지를 터치하여 진행해야합니다. 이 병리학 적 상황은 우연히 일어날 가능성이 적습니다.
TLB (및 페이지 워커 내부)는 일부 페이지 테이블 데이터를 캐시 할 수 있으며 OS invlpg
에서 새 CR3 최상위 페이지 디렉토리를 설정 하지 않은 경우 페이지 워크를 처음부터 다시 시작할 필요가 없습니다 . 존재하지 않는 페이지에서 현재 페이지로 페이지를 변경할 때 이들 중 어느 것도 필요하지 않습니다. x86 on paper는 그것이 필요하지 않다는 것을 보장합니다 (따라서 현재 존재하지 않는 PTE의 "네거티브 캐싱"은 허용되지 않으며 최소한 소프트웨어에는 보이지 않습니다). 따라서 게스트 물리적 페이지 테이블 페이지 중 일부가 실제로 존재하지 않더라도 CPU가 VMexit하지 않을 수 있습니다.
PMU 성능 카운터 는 명령어가 해당 명령어 의 PEBS 버퍼 에 쓰려면 perf 이벤트가 필요하도록 활성화 및 구성 할 수 있습니다 . 커널이 아닌 사용자 공간 명령 만 계산하도록 카운터 마스크를 구성하면 사용자 공간으로 돌아올 때마다 카운터가 오버플로되고 샘플이 버퍼에 저장되어 페이지 오류가 발생할 수 있습니다.