Intel Dunia Virtual. Bagian 2: SMP

Dalam artikel sebelumnya (tautan), saya berbicara tentang konsep dasar hypervisor berdasarkan teknologi virtualisasi perangkat keras Intel. Sekarang saya mengusulkan memperluas kemampuan hypervisor dengan menambahkan dukungan untuk arsitektur multiprosesor (SMP), dan juga mempertimbangkan contoh bagaimana hypervisor dapat membuat perubahan pada OS tamu.

Semua tindakan lebih lanjut akan dilakukan pada PC dengan konfigurasi berikut:

CPU: Intel Core i7 5820K
Motherboard: Asus X99-PRO
Ram: 16GB
OS Tamu: Windows 7 x32 dengan PAE Dinonaktifkan

Saya akan mulai dengan menjelaskan lokasi komponen hypervisor pada hard drive (semua nilai ditentukan dalam sektor).

gambar
Proses memuat hypervisor berbeda dari versi sebelumnya hanya di hadapan modul hypervisor.ap baru , yang tujuannya adalah inisialisasi dasar prosesor AP.

Proses memuat modul ke dalam memori:



Dukungan SMP

Saya menerapkan hypervisor pada prinsip multiprosesor simetris, yang berarti bahwa salinan VMX yang sama akan diluncurkan pada semua prosesor logis yang ada. Selain itu, tabel IDT dan GDT, serta tabel untuk memori paging, akan umum untuk semua prosesor logis. Saya melakukan ini karena hypervisor akan segera menginisialisasi memori untuk ruang alamat OS tamu dan tidak perlu secara dinamis menugaskan kembali alamat fisik setiap halaman. Juga, dengan pendekatan ini, Anda tidak perlu memantau korespondensi cache TLB prosesor di sisi hypervisor.
Proses inisialisasi untuk BSP dan AP akan berbeda. Semua struktur utama yang terlibat dalam hypervisor akan dibuat selama inisialisasi BSP. Selain itu, status Aktivitas untuk prosesor AP mode vmx non root akan diatur ke status HLT. Dengan demikian, lingkungan OS tamu akan ditiru sesuai dengan apa yang akan terjadi tanpa menggunakan virtualisasi.

Inisialisasi BSP:

  1. Inisialisasi spinlock
  2. Menginisialisasi dan memuat tabel GDT dan IDT
  3. Inisialisasi Tabel Paging
  4. Menginisialisasi Struktur VMCS dan Membuat Tabel EPT Umum
  5. Aktivasi prosesor AP. Untuk melakukan ini, urutan interupsi INIT - SIPI dikirim ke setiap AP. Vektor untuk interupsi SIPI adalah 0x20, yang sesuai dengan transfer kontrol AP pada 0x20000 (modul hypervisor.ap)
  6. Memulai OS tamu di 0x7C00 (modul win7.mbr)

AP inisialisasi:

  1. Setelah mengaktifkan AP, prosesor berada dalam mode nyata. Modul hypervisor.ap menginisialisasi memori dan tabel paging untuk beralih ke mode lama
  2. Unduh IDT, GDT, serta katalog paging tables yang dibuat selama fase inisialisasi BSP
  3. Inisialisasi struktur VMCS, dan memuat tabel EPT dibuat pada tahap inisialisasi BSP
  4. Beralih ke mode non-root vmx dengan status HLT aktif

Kita dapat mengatakan bahwa implementasi dukungan SMP di hypervisor cukup sederhana, tetapi ada beberapa poin yang ingin saya perhatikan.

1. Dukungan USB Legacy

Model motherboard baru mungkin tidak memiliki konektor PS / 2, jadi Dukungan USB Legacy digunakan untuk memastikan kompatibilitas ke belakang. Ini berarti Anda dapat bekerja dengan keyboard atau mouse usb menggunakan metode yang sama (port input / output) seperti halnya dengan standar PS / 2. Implementasi Dukungan USB Legacy tidak hanya tergantung pada model motherboard, tetapi juga dapat mengisyaratkan dalam berbagai versi firmware. Pada motherboard Asus X99-PRO saya, Dukungan USB Legacy diimplementasikan melalui interupsi SMI, di prosesor yang emulasi PS / 2 terjadi. Saya menulis tentang hal ini dengan sangat rinci, karena dalam kasus saya (firmware versi 3801), Dukungan USB Legacy tidak kompatibel dengan mode lama dan ketika kembali dari SMM, prosesor masuk ke kondisi mati.

Solusi termudah dalam situasi ini adalah mematikan Dukungan USB Legacy sebelum beralih ke mode lama. Namun, di Windows, metode polling keyboard PS / 2 digunakan pada tahap memilih opsi boot, sehingga Dukungan USB Legacy harus diaktifkan kembali sebelum OS tamu mulai memuat.

2. Peralihan Tugas Perangkat Keras

Dalam sistem operasi modern, beralih antar tugas diimplementasikan, sebagai aturan, dengan metode perangkat lunak. Namun, pada Windows7, penyeleksi yang menunjuk ke TSS ditugaskan untuk menginterupsi 2 - NMI dan 8 - Double Fault, yang berarti bahwa interupsi tersebut akan menyebabkan pengalihan konteks perangkat keras. Intel VMX tidak mendukung Peralihan Tugas perangkat keras, dan upaya untuk mengeksekusinya menyebabkan VM Exit. Untuk kasus-kasus seperti itu, saya menulis pengendali Task Switch saya (fungsi GuestTaskSwitch). Gangguan Double Fault hanya terjadi jika terjadi konflik sistem yang serius yang disebabkan oleh penanganan gangguan lainnya secara tidak tepat. Dalam proses debugging, saya tidak menemukan itu. Tetapi NMI muncul pada prosesor AP pada saat me-reboot Windows. Ini masih membuat saya ragu karena tidak jelas apakah NMI ini adalah hasil dari proses reboot biasa atau ini operasi hypervisor yang salah pada beberapa tahapan sebelumnya. Jika Anda memiliki informasi tentang masalah ini, silakan berbicara dalam komentar atau tulis saya di pesan pribadi.

Perubahan pada OS tamu

Sejujurnya, saya tidak bisa memutuskan untuk waktu yang lama apa perubahan hypervisor seharusnya dalam karya OS tamu. Faktanya adalah bahwa di satu sisi saya ingin menunjukkan sesuatu yang menarik, seperti pengenalan penangan kami dalam protokol jaringan dasar, tetapi di sisi lain, semuanya akan turun ke sejumlah besar kode, dan ada sedikit hubungannya dengan subjek hypervisor. Selain itu, saya tidak ingin mengikat hypervisor ke set besi tertentu.

Akibatnya, kompromi berikut ditemukan: dalam versi hypervisor ini, kontrol atas panggilan sistem dari mode pengguna diimplementasikan, dengan kata lain, akan dimungkinkan untuk mengontrol operasi aplikasi yang berjalan di OS tamu. Jenis kontrol ini cukup sederhana untuk diterapkan dan selain itu memungkinkan Anda untuk mendapatkan hasil visual dari pekerjaan.

Kontrol atas pengoperasian aplikasi akan dilakukan pada tingkat panggilan sistem. Dan tujuan utamanya adalah untuk mengubah hasil dari fungsi NtQuerySystemInformation sehingga ketika Anda menelepon dengan argumen SystemProcessInformation ( 0x05 ), Anda dapat memotong informasi proses.

Pada Windows 7, program aplikasi untuk memanggil fungsi sistem menggunakan perintah assembler sysenter, setelah itu kontrol ditransfer ke prosesor KiFastCallEntry ke kernel pada level r0. Untuk kembali ke level aplikasi r3, gunakan perintah sysexit.
Untuk mendapatkan akses ke hasil eksekusi fungsi NtQuerySystemInformation, perlu untuk menyimpan nomor fungsi yang dipanggil setiap kali perintah sysenter dijalankan. Kemudian, ketika menjalankan sysexit, bandingkan nilai yang disimpan dengan jumlah fungsi yang dicegat dan, jika ada kecocokan, buat perubahan pada data yang dikembalikan oleh fungsi.
Intel VMX tidak menyediakan cara langsung untuk memantau pelaksanaan sysenter / sysexit , namun, jika Anda menulis nilai 0 ke Guest MSR IA32_SYSENTER_CS , maka perintah sysenter / sysexit akan menaikkan pengecualian GP yang dapat digunakan untuk memanggil VM Exit handler. Agar pengecualian GP untuk memanggil VM Exit, Anda perlu mengatur 13 bit di bidang Exception Bitmap dari VMCS.

Struktur di bawah ini digunakan untuk meniru pasangan sysenter / sysexit.

typedef struct{ QWORD ServiceNumber; QWORD Guest_Sys_CS; QWORD Guest_Sys_EIP; QWORD Guest_Sys_ESP; } SysEnter_T; 

Bidang ServiceNumber berisi jumlah fungsi yang dipanggil dan diperbarui dengan setiap panggilan ke sysenter.

Bidang Guest_Sys_CS, Guest_Sys_EIP, Guest_Sys_ESP diperbarui ketika OS tamu mencoba menulis ke register MSR yang sesuai. Untuk melakukan ini, tulis masker di Alamat MSR-Bitmap .

 // 174H 372 IA32_SYSENTER_CS SYSENTER_CS write mask ptrMSR_BMP[0x100 + (0x174 >> 6)] |= (1UL << (0x174 & 0x3F)); // 175H 373 IA32_SYSENTER_ESP SYSENTER_ESP write mask ptrMSR_BMP[0x100 + (0x175 >> 6)] |= (1UL << (0x175 & 0x3F)); // 176H 374 IA32_SYSENTER_EIP SYSENTER_EIP write mask ptrMSR_BMP[0x100 + (0x176 >> 6)] |= (1UL << (0x176 & 0x3F)); 

OS tamu seharusnya tidak melihat perubahan yang dibuat oleh hypervisor untuk pengoperasian panggilan fungsi sistem. Dengan mengatur topeng baca untuk MSR IA32_SYSENTER_CS, Anda dapat mengembalikan OS tamu ke nilai register aslinya saat membaca.

 // 174H 372 IA32_SYSENTER_CS SYSENTER_CS read mask ptrMSR_BMP[0x174 >> 6] |= (1UL << (0x174 & 0x3F)); 

Berikut ini adalah skema emulasi perintah sysenter / sysexit .



Pada tahap emulasi sysexit , jumlah yang tersimpan dari fungsi yang dipanggil dibandingkan dengan nomor NtQuerySystemInformation (0x105). Dalam kasus pertandingan, diverifikasi bahwa NtQuerySystemInformation disebut dengan argumen Informasi Proses Sistem dan jika demikian, fungsi ChangeProcessNames (DWORD SPI_GVA, DWORD SPI_size) membuat perubahan pada struktur yang berisi informasi tentang proses.
SPI_GVA adalah alamat virtual tamu dari struktur SYSTEM_PROCESS_INFORMATION
SPI_size adalah ukuran total struktur dalam byte.
Struktur SYSTEM_PROCESS_INFORMATION sendiri terlihat seperti ini:

 typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; BYTE Reserved1[48]; UNICODE_STRING ImageName; KPRIORITY BasePriority; HANDLE UniqueProcessId; PVOID Reserved2; ULONG HandleCount; ULONG SessionId; PVOID Reserved3; SIZE_T PeakVirtualSize; SIZE_T VirtualSize; ULONG Reserved4; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; PVOID Reserved5; SIZE_T QuotaPagedPoolUsage; PVOID Reserved6; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER Reserved7[6]; } SYSTEM_PROCESS_INFORMATION; 

Tidak ada yang rumit dalam penguraiannya, yang terpenting adalah jangan lupa menerjemahkan alamat virtual tamu menjadi fisik, untuk ini digunakan fungsi GuestLinAddrToPhysAddr () .

Untuk lebih jelasnya, saya mengganti dua karakter pertama dalam nama-nama semua proses dengan tanda ' :) '. Hasil penggantian seperti itu terlihat di tangkapan layar.



Ringkasan

Secara umum, tugas yang ditetapkan pada awal artikel selesai. Hypervisor memastikan pengoperasian OS tamu yang stabil, dan juga mengontrol panggilan fungsi sistem dari level aplikasi. Saya perhatikan bahwa kelemahan utama menggunakan emulasi perintah sysenter / sysexit adalah peningkatan yang signifikan dalam panggilan VM Exit, yang mempengaruhi kinerja dan ini terutama terlihat ketika OS tamu dalam mode prosesor tunggal. Kerugian ini dapat dihilangkan jika Anda mengontrol panggilan hanya dalam konteks proses yang dipilih.

Dan itu saja untuk saat ini. Sumber untuk artikel dapat diambil di sini

Terima kasih atas perhatian anda

Source: https://habr.com/ru/post/id429918/


All Articles