Antarmuka Hypercall

Hypervisor menyediakan mekanisme panggilan untuk tamu. Panggilan tersebut disebut sebagai hypercalls. Setiap hypercall mendefinisikan sekumpulan parameter input dan/atau output. Parameter ini ditentukan dalam hal struktur data berbasis memori. Semua elemen struktur data input dan output diisi ke batas alami hingga 8 byte (yaitu, elemen dua byte harus berada di batas dua byte dan sebagainya).

Konvensi panggilan hypercall kedua secara opsional dapat digunakan untuk subset hypercalls – khususnya, yang memiliki dua atau lebih sedikit parameter input dan tidak ada parameter output. Saat menggunakan konvensi panggilan ini, parameter input diteruskan dalam register tujuan umum.

Konvensi panggilan hypercall ketiga secara opsional dapat digunakan untuk subset hypercalls di mana blok parameter input hingga 112 byte. Saat menggunakan konvensi panggilan ini, parameter input diteruskan dalam register, termasuk register XMM yang volatil.

Struktur data input dan output harus ditempatkan dalam memori pada batas 8 byte dan diisi ke kelipatan 8 byte dalam ukuran. Nilai dalam wilayah padding diabaikan oleh hypervisor.

Untuk output, hypervisor diizinkan untuk (tetapi tidak dijamin untuk) menimpa wilayah padding. Jika menimpa wilayah padding, itu akan menulis nol.

Kelas Hypercall

Ada dua kelas hypercalls: sederhana dan rep (singkatan dari "repeat"). Hypercall sederhana melakukan operasi tunggal dan memiliki sekumpulan parameter input dan output ukuran tetap. Rep hypercall bertindak seperti serangkaian hypercalls sederhana. Selain sekumpulan parameter input dan output berukuran tetap, rep hypercalls melibatkan daftar elemen input dan/atau output ukuran tetap.

Ketika pemanggil awalnya memanggil rep hypercall, penelepon menentukan jumlah rep yang menunjukkan jumlah elemen dalam daftar parameter input dan/atau output. Penelepon juga menentukan indeks mulai rep yang menunjukkan elemen input dan/atau output berikutnya yang harus digunakan. Hypervisor memproses parameter rep dalam urutan daftar - yaitu, dengan meningkatkan indeks elemen.

Untuk pemanggilan hypercall rep berikutnya, indeks mulai rep menunjukkan berapa banyak elemen yang telah selesai - dan, bersama dengan nilai jumlah rep - berapa banyak elemen yang tersisa. Misalnya, jika pemanggil menentukan jumlah rep 25, dan hanya 20 iterasi yang selesai dalam batasan waktu, hypercall mengembalikan kontrol kembali ke prosesor virtual panggilan setelah memperbarui indeks mulai rep menjadi 20. Ketika hypercall dijalankan kembali, hypervisor akan dilanjutkan pada elemen 20 dan menyelesaikan 5 elemen yang tersisa.

Jika kesalahan ditemui saat memproses elemen, kode status yang sesuai disediakan bersama dengan jumlah reps selesai, menunjukkan jumlah elemen yang berhasil diproses sebelum kesalahan ditemui. Dengan asumsi kata kontrol hypercall yang ditentukan valid (lihat yang berikut) dan daftar parameter input/output dapat diakses, hypervisor dijamin akan mencoba setidaknya satu rep, tetapi tidak diperlukan untuk memproses seluruh daftar sebelum mengembalikan kontrol kembali ke pemanggil.

Kelanjutan Hypercall

Hypercall dapat dianggap sebagai instruksi kompleks yang membutuhkan banyak siklus. Hypervisor mencoba membatasi eksekusi hypercall hingga 50μs atau kurang sebelum mengembalikan kontrol ke prosesor virtual yang memanggil hypercall. Beberapa operasi hypercall cukup kompleks sehingga jaminan 50μs sulit dibuat. Oleh karena itu hypervisor bergantung pada mekanisme kelanjutan hypercall untuk beberapa hypercalls - termasuk semua bentuk rep hypercall.

Mekanisme kelanjutan hypercall sebagian besar transparan bagi pemanggil. Jika hypercall tidak dapat diselesaikan dalam batas waktu yang ditentukan, kontrol dikembalikan ke pemanggil, tetapi pointer instruksi tidak dimajukan melewati instruksi yang memanggil hypercall. Ini memungkinkan interupsi yang tertunda untuk ditangani dan prosesor virtual lainnya dijadwalkan. Ketika utas panggilan asli melanjutkan eksekusi, utas tersebut akan menjalankan kembali instruksi hypercall dan meneruskan kemajuan menuju penyelesaian operasi.

Sebagian besar hypercalls sederhana dijamin selesai dalam batas waktu yang ditentukan. Namun, sejumlah kecil hypercalls sederhana mungkin memerlukan lebih banyak waktu. Hypercalls ini menggunakan kelanjutan hypercall dengan cara yang sama untuk merep hypercalls. Dalam kasus seperti itu, operasi melibatkan dua atau lebih status internal. Pemanggilan pertama menempatkan objek (misalnya, partisi atau prosesor virtual) ke dalam satu status, dan setelah pemanggilan berulang, status akhirnya beralih ke status terminal. Untuk setiap hypercall yang mengikuti pola ini, efek samping yang terlihat dari status internal perantara dijelaskan.

Atomitas dan Pemesanan Hypercall

Kecuali jika dicatat, tindakan yang dilakukan oleh hypercall adalah atom keduanya sehubungan dengan semua operasi tamu lainnya (misalnya, instruksi yang dijalankan dalam tamu) dan semua hypercalls lainnya dijalankan pada sistem. Hypercall sederhana melakukan satu tindakan atom; rep hypercall melakukan beberapa tindakan atom independen.

Hypercalls sederhana yang menggunakan kelanjutan hypercall dapat melibatkan beberapa status internal yang terlihat secara eksternal. Panggilan tersebut terdiri dari beberapa operasi atomik.

Setiap tindakan hypercall dapat membaca parameter input dan/atau menulis hasil. Input untuk setiap tindakan dapat dibaca pada granularitas apa pun dan kapan saja setelah hypercall dibuat dan sebelum tindakan dijalankan. Hasilnya (yaitu, parameter output) yang terkait dengan setiap tindakan dapat ditulis pada granularitas apa pun dan kapan saja setelah tindakan dijalankan dan sebelum hypercall kembali.

Tamu harus menghindari pemeriksaan dan/atau manipulasi parameter input atau output apa pun yang terkait dengan hypercall yang dijalankan. Sementara prosesor virtual yang menjalankan hypercall tidak akan mampu melakukannya (karena eksekusi tamunya ditangguhkan sampai hypercall kembali), tidak ada yang mencegah prosesor virtual lainnya melakukannya. Tamu yang berulah dengan cara ini dapat menabrak atau menyebabkan kerusakan dalam partisi mereka.

Hypercalls hanya dapat dipanggil dari mode prosesor tamu yang paling istimewa. Pada platform x64, ini berarti mode terlindungi dengan tingkat hak istimewa (CPL) saat ini nol. Meskipun kode mode nyata berjalan dengan CPL nol yang efektif, hypercalls tidak diizinkan dalam mode nyata. Upaya untuk memanggil hypercall dalam mode prosesor ilegal akan menghasilkan pengecualian #UD (operasi yang tidak terdefinisi) pada x64, dan pengecualian instruksi yang tidak ditentukan pada ARM64.

Semua hypercalls harus dipanggil melalui antarmuka hypercall yang ditentukan secara arsitektur (lihat di bawah). Upaya untuk memanggil hypercall dengan cara lain (misalnya, menyalin kode dari halaman kode hypercall ke lokasi alternatif dan menjalankannya dari sana) dapat mengakibatkan pengecualian operasi yang tidak ditentukan (#UD). Hypervisor tidak dijamin untuk memberikan pengecualian ini.

Persyaratan Perataan

Penelepon harus menentukan alamat fisik tamu (IPK) 64-bit dari parameter input dan/atau output. Penunjuk GPA harus selaras 8 byte. Jika hypercall tidak melibatkan parameter input atau output, hypervisor mengabaikan pointer GPA yang sesuai.

Daftar parameter input dan output tidak dapat tumpang tindih atau batas halaman silang. Halaman input dan output Hypercall diharapkan menjadi halaman GPA dan bukan halaman "overlay". Jika prosesor virtual menulis parameter input ke halaman overlay dan menentukan GPA dalam halaman ini, akses hypervisor ke daftar parameter input tidak ditentukan.

Hypervisor akan memvalidasi bahwa partisi panggilan dapat membaca dari halaman input sebelum menjalankan hypercall yang diminta. Validasi ini terdiri dari dua pemeriksaan: GPA yang ditentukan dipetakan dan GPA ditandai dapat dibaca. Jika salah satu pengujian ini gagal, hypervisor menghasilkan pesan intersepsi memori. Untuk hypercalls yang memiliki parameter output, hypervisor akan memvalidasi bahwa partisi dapat menulis ke halaman output. Validasi ini terdiri dari dua pemeriksaan: GPA yang ditentukan dipetakan dan GPA ditandai dapat ditulis.

Input Hypercall

Penelepon menentukan hypercall dengan nilai 64-bit yang disebut nilai input hypercall. Ini diformat sebagai berikut:

Bidang Bit Informasi yang Disediakan
Kode Panggilan 15-0 Menentukan hypercall mana yang diminta
Cepat 16 Menentukan apakah hypercall menggunakan konvensi panggilan berbasis register: 0 = berbasis memori, 1 = berbasis register
Ukuran header variabel 26-17 Ukuran header variabel, dalam QWORDS.
RsvdZ 30-27 Harus nol
Berlapis 31 Menentukan hypercall harus ditangani oleh hypervisor L0 di lingkungan berlapis.
Jumlah Rep 43-32 Jumlah total rep (untuk panggilan rep, harus nol jika tidak)
RsvdZ 47-44 Harus nol
Indeks Mulai Rep 59-48 Indeks awal (untuk panggilan rep, harus nol jika tidak)
RsvdZ 63-60 Harus nol

Untuk rep hypercalls, bidang jumlah rep menunjukkan jumlah total rep. Indeks mulai rep menunjukkan pengulangan tertentu relatif terhadap awal daftar (nol menunjukkan bahwa elemen pertama dalam daftar akan diproses). Oleh karena itu, nilai jumlah rep harus selalu lebih besar dari indeks mulai rep.

Konvensi Pendaftaran Hypercall (x86/x64)

Pada x86/x64, daftarkan pemetaan untuk input hypercall saat bendera Cepat adalah nol adalah sebagai berikut:

x64 x86 Informasi yang Disediakan
RCX EDX:EAX Nilai Input Hypercall
RDX EBX:ECX GPA Parameter Input
R8 EDI:ESI PARAMETER Output GPA

Nilai input hypercall diteruskan dalam register bersama dengan GPA yang menunjuk ke parameter input dan output.

Pemetaan register bergantung pada apakah pemanggil berjalan dalam mode 32-bit (x86) atau 64-bit (x64). Hypervisor menentukan mode pemanggil berdasarkan nilai EFER. LMA dan CS.L. Jika kedua bendera ini diatur, pemanggil diasumsikan sebagai pemanggil 64-bit.

Daftarkan pemetaan untuk input hypercall saat bendera Cepat adalah satu:

x64 x86 Informasi yang Disediakan
RCX EDX:EAX Nilai Input Hypercall
RDX EBX:ECX Parameter Masukan
R8 EDI:ESI Output Parameter

Nilai input hypercall diteruskan dalam register bersama dengan parameter input.

Konvensi Pendaftaran Hypercall (ARM64 SMCCC)

Pada ARM64, hypercalls dijalankan menggunakan instruksi "HVC #0". Panggilan mematuhi ARM64 SMCCC (Konvensi Panggilan SMC).

Daftarkan pemetaan untuk input hypercall adalah sebagai berikut:

Register Informasi yang Disediakan
X0 Pengidentifikasi Fungsi SMCCC
X1 Nilai Input Hypercall
X2 GPA Parameter Input
X3 PARAMETER Output GPA

Pengidentifikasi Fungsi SMCCC di X0 mengikuti format ini:

Bit Bidang Nilai Description
31 Menghasilkan Panggilan 0 Selalu 0
30 Konvensi Panggilan 1 1 untuk konvensi panggilan HVC64
29:24 Jenis Panggilan Layanan 6 6 untuk Panggilan Layanan Hypervisor Spesifik Vendor
23:16 Sudah Dipesan 0 Dicadangkan, harus nol (Res0)
15:0 Nomor Fungsi 1 1 menunjukkan kode panggilan HV didefinisikan dalam X1

Format Pengidentifikasi Fungsi lengkap: 0x46000001

Konvensi Pendaftaran Hypercall (ARM64 HVC #1)

Untuk alasan historis, antarmuka hypervisor ARM64 juga mendukung konvensi panggilan yang berbeda. Hypercalls dijalankan dengan instruksi "HVC #1". Sebaiknya gunakan konvensi panggilan SMCCC untuk kode baru.

Daftarkan pemetaan untuk input hypercall adalah sebagai berikut:

Register Informasi yang Disediakan
X0 Nilai Input Hypercall
X1 GPA Parameter Input
X2 PARAMETER Output GPA

Header Input Hypercall Berukuran Variabel

Sebagian besar header input hypercall memiliki ukuran tetap. Jumlah data header yang diteruskan dari tamu ke hypervisor oleh karena itu secara implisit ditentukan oleh kode hypercall dan tidak perlu ditentukan secara terpisah. Namun, beberapa hypercalls memerlukan jumlah variabel data header. Hypercalls ini biasanya memiliki header input ukuran tetap dan input header tambahan yang berukuran variabel.

Header berukuran variabel mirip dengan input hypercall tetap (diselaraskan ke 8 byte dan berukuran ke kelipatan 8 byte). Pemanggil harus menentukan berapa banyak data yang disediakannya sebagai header input. Ukuran ini disediakan sebagai bagian dari nilai input hypercall (lihat "Ukuran header variabel" dalam tabel di atas).

Karena ukuran header tetap implisit, alih-alih menyediakan ukuran header total, hanya bagian variabel yang disediakan dalam kontrol input:

Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} rounded up to nearest multiple of 8

Variable Header Size = Variable Header Bytes / 8

Adalah ilegal untuk menentukan ukuran header variabel non-nol untuk hypercall yang tidak didokumenkan secara eksplisit sebagai menerima header input berukuran variabel. Dalam kasus seperti itu, hypercall akan menghasilkan kode HV_STATUS_INVALID_HYPERCALL_INPUTpengembalian .

Ada kemungkinan bahwa untuk pemanggilan hypercall tertentu yang menerima header input berukuran variabel yang semua input header sepenuhnya cocok dalam header ukuran tetap. Dalam kasus seperti itu, header input berukuran variabel berukuran nol dan bit yang sesuai dalam input hypercall harus diatur ke nol.

Dalam semua hal lain, hypercalls yang menerima header input berukuran variabel serupa dengan hypercalls header input ukuran tetap sehubungan dengan konvensi panggilan. Dimungkinkan juga untuk hypercall header berukuran variabel untuk juga mendukung semantik rep. Dalam kasus seperti itu, elemen rep terletak setelah header dengan cara biasa, kecuali bahwa ukuran total header mencakup bagian tetap dan variabel. Semua aturan lain tetap sama, misalnya elemen rep pertama harus selaras 8 byte.

Input XMM Fast Hypercall (x86/x64)

Pada platform x86/x64, hypervisor mendukung penggunaan hypercalls cepat XMM, yang memungkinkan beberapa hypercalls untuk memanfaatkan peningkatan performa antarmuka hypercall cepat meskipun membutuhkan lebih dari dua parameter input. Antarmuka hypercall cepat XMM menggunakan enam register XMM untuk memungkinkan pemanggil meneruskan blok parameter input hingga ukuran 112 byte.

Ketersediaan antarmuka hypercall cepat XMM ditunjukkan melalui Daun CPUID "Identifikasi Fitur Hypervisor" (0x40000003):

  • Bit 4: dukungan untuk meneruskan input hypercall melalui register XMM tersedia.

Perhatikan bahwa ada bendera terpisah untuk menunjukkan dukungan untuk output cepat XMM. Setiap upaya untuk menggunakan antarmuka ini ketika hypervisor tidak menunjukkan ketersediaan akan mengakibatkan kesalahan #UD.

Mendaftarkan Pemetaan (Hanya Input)

x64 x86 Informasi yang Disediakan
RCX EDX:EAX Nilai Input Hypercall
RDX EBX:ECX Blok Parameter Input
R8 EDI:ESI Blok Parameter Input
XMM0 XMM0 Blok Parameter Input
XMM1 XMM1 Blok Parameter Input
XMM2 XMM2 Blok Parameter Input
XMM3 XMM3 Blok Parameter Input
XMM4 XMM4 Blok Parameter Input
XMM5 XMM5 Blok Parameter Input

Nilai input hypercall diteruskan dalam register bersama dengan parameter input. Pemetaan register bergantung pada apakah pemanggil berjalan dalam mode 32-bit (x86) atau 64-bit (x64). Hypervisor menentukan mode pemanggil berdasarkan nilai EFER. LMA dan CS.L. Jika kedua bendera ini diatur, pemanggil diasumsikan sebagai pemanggil 64-bit. Jika blok parameter input lebih kecil dari 112 byte, byte tambahan apa pun dalam register diabaikan.

Mendaftarkan Input Panggilan Cepat (ARM64 SMCCC)

Pada platform ARM64, hypervisor mendukung penggunaan register fast hypercalls, yang memungkinkan beberapa hypercalls untuk memanfaatkan peningkatan performa antarmuka hypercall cepat meskipun mereka membutuhkan lebih dari dua parameter input. Antarmuka register fast hypercall menggunakan 16 register tujuan umum untuk memungkinkan penelepon meneruskan blok parameter input hingga ukuran 128 byte.

Mendaftarkan Pemetaan (Hanya Input)

Register Informasi yang Disediakan
X0 Pengidentifikasi Fungsi SMCCC
X1 Nilai Input Hypercall
X2 - X17 Blok Parameter Input

Jika blok parameter input lebih kecil dari 128 byte, byte tambahan apa pun dalam register diabaikan.

Daftarkan Input Panggilan Cepat (ARM64 HVC #1)

Antarmuka register fast hypercall menggunakan enam belas register tujuan umum untuk memungkinkan penelepon meneruskan blok parameter input hingga ukuran 128 byte.

Mendaftarkan Pemetaan (Hanya Input)

Register Informasi yang Disediakan
X0 Nilai Input Hypercall
X1 - X17 Blok Parameter Input

Jika blok parameter input lebih kecil dari 128 byte, byte tambahan apa pun dalam register diabaikan.

Output Hypercall

Semua hypercalls mengembalikan nilai 64-bit yang disebut nilai hasil hypercall. Ini diformat sebagai berikut:

Bidang Bit Comment
Result 15-0 HV_STATUS kode yang menunjukkan keberhasilan atau kegagalan
Rsvd 31-16 Penelepon harus mengabaikan nilai dalam bit ini
Reps selesai 43-32 Jumlah rep yang berhasil diselesaikan
RsvdZ 63-40 Penelepon harus mengabaikan nilai dalam bit ini

Untuk rep hypercalls, bidang reps complete adalah jumlah total reps selesai dan tidak relatif terhadap indeks mulai rep. Misalnya, jika penelepon menentukan indeks mulai rep 5, dan jumlah rep 10, bidang reps complete akan menunjukkan 10 setelah berhasil diselesaikan.

Nilai hasil hypercall diteruskan kembali dalam register.

Pada x64, pemetaan register tergantung pada apakah pemanggil berjalan dalam mode 32-bit (x86) atau 64-bit (x64) (lihat di atas). Pemetaan register untuk output hypercall adalah sebagai berikut:

x64 x86 Informasi yang Disediakan
RAX EDX:EAX Nilai Hasil Hypercall

Pada ARM64, pemetaan register untuk output hypercall adalah sebagai berikut:

Register Informasi yang Disediakan
X0 Nilai Hasil Hypercall

Output XMM Fast Hypercall (x86/x64)

Mirip dengan bagaimana hypervisor mendukung input hypercall cepat XMM, register yang sama dapat dibagikan untuk mengembalikan output. Ini hanya didukung pada platform x64.

Kemampuan untuk mengembalikan output melalui register XMM ditunjukkan melalui Daun CPUID "Identifikasi Fitur Hypervisor" (0x40000003):

  • Bit 15: dukungan untuk mengembalikan output hypercall melalui register XMM tersedia.

Perhatikan bahwa ada bendera terpisah untuk menunjukkan dukungan untuk input cepat XMM. Setiap upaya untuk menggunakan antarmuka ini ketika hypervisor tidak menunjukkan ketersediaan akan mengakibatkan kesalahan #UD.

Mendaftarkan Pemetaan (Input dan Output)

Register yang tidak digunakan untuk meneruskan parameter input dapat digunakan untuk mengembalikan output. Dengan kata lain, jika blok parameter input lebih kecil dari 112 byte (dibulatkan ke potongan selaras 16 byte terdekat), register yang tersisa akan mengembalikan output hypercall.

x64 Informasi yang Disediakan
RDX Blok Input atau Output
R8 Blok Input atau Output
XMM0 Blok Input atau Output
XMM1 Blok Input atau Output
XMM2 Blok Input atau Output
XMM3 Blok Input atau Output
XMM4 Blok Input atau Output
XMM5 Blok Input atau Output

Misalnya, jika blok parameter input berukuran 20 byte, hypervisor akan mengabaikan 12 byte berikut. 80 byte yang tersisa akan berisi output hypercall (jika berlaku).

Mendaftarkan Output Panggilan Cepat (ARM64 SMCCC)

Pada platform ARM64, mirip dengan bagaimana hypervisor mendukung pendaftaran input hypercall cepat, register yang sama dapat dibagikan untuk mengembalikan output.

Mendaftarkan Pemetaan (Input dan Output)

Register yang tidak digunakan untuk meneruskan parameter input dapat digunakan untuk mengembalikan output. Dengan kata lain, jika blok parameter input lebih kecil dari 128 byte (dibulatkan ke potongan selaras 8 byte terdekat), register yang tersisa akan mengembalikan output hypercall.

Register Informasi yang Disediakan
X2 - X17 Blok Input atau Output

Misalnya, jika blok parameter input berukuran 20 byte, hypervisor akan mengabaikan 4 byte berikut. 104 byte yang tersisa akan berisi output hypercall (jika berlaku).

Mendaftarkan Output Panggilan Cepat (ARM64 HVC #1)

Mirip dengan versi SMCCC, antarmuka HVC #1 menggunakan register yang sama untuk mengembalikan output.

Mendaftarkan Pemetaan (Input dan Output)

Register yang tidak digunakan untuk meneruskan parameter input dapat digunakan untuk mengembalikan output. Dengan kata lain, jika blok parameter input lebih kecil dari 128 byte (dibulatkan ke potongan selaras 8 byte terdekat), register yang tersisa akan mengembalikan output hypercall.

Register Informasi yang Disediakan
X1 - X17 Blok Input atau Output

Misalnya, jika blok parameter input berukuran 20 byte, hypervisor akan mengabaikan 4 byte berikut. 104 byte yang tersisa akan berisi output hypercall (jika berlaku).

Volatile Registers (x86/x64)

Hypercalls hanya akan mengubah nilai register yang ditentukan dalam kondisi berikut:

  1. RAX (x64) dan EDX:EAX (x86) selalu ditimpa dengan nilai hasil hypercall dan parameter output, jika ada.
  2. Rep hypercalls akan memodifikasi RCX (x64) dan EDX:EAX (x86) dengan indeks mulai rep baru.
  3. HvCallSetVpRegisters dapat memodifikasi register apa pun yang didukung dengan hypercall tersebut.
  4. RDX, R8, dan XMM0 hingga XMM5, ketika digunakan untuk input hypercall cepat, tetap tidak dimodifikasi. Namun, register yang digunakan untuk output hypercall cepat dapat dimodifikasi, termasuk RDX, R8, dan XMM0 hingga XMM5. Hyper-V hanya akan memodifikasi register ini untuk output hypercall cepat, yang terbatas pada x64.

Volatile Registers (ARM64 SMCCC)

Hypercalls hanya akan mengubah nilai register yang ditentukan dalam kondisi berikut:

  1. X0 selalu ditimpa dengan nilai hasil hypercall dan parameter output, jika ada.
  2. Rep hypercalls akan memodifikasi X1 dengan indeks mulai rep baru.
  3. HvCallSetVpRegisters dapat memodifikasi register apa pun yang didukung dengan hypercall tersebut.
  4. X2 - X17, saat digunakan untuk input hypercall cepat, tetap tidak dimodifikasi. Namun, register yang digunakan untuk output hypercall cepat dapat dimodifikasi, termasuk X2 - X17. Hyper-V hanya akan memodifikasi register ini untuk output hypercall cepat.

Volatile Registers (ARM64 HVC #1)

Hypercalls hanya akan mengubah nilai register yang ditentukan dalam kondisi berikut:

  1. X0 selalu ditimpa dengan nilai hasil hypercall dan parameter output, jika ada.
  2. Rep hypercalls akan memodifikasi X0 dengan indeks mulai rep baru.
  3. HvCallSetVpRegisters dapat memodifikasi register apa pun yang didukung dengan hypercall tersebut.
  4. X1 - X17, ketika digunakan untuk input hypercall cepat, tetap tidak dimodifikasi. Namun, register yang digunakan untuk output hypercall cepat dapat dimodifikasi, termasuk X1 - X17. Hyper-V hanya akan memodifikasi register ini untuk output hypercall cepat.

Pembatasan Hypercall

Hypercalls mungkin memiliki batasan terkait yang harus dipenuhi bagi mereka untuk melakukan fungsi yang dimaksudkan. Jika semua batasan tidak terpenuhi, hypercall akan berakhir dengan kesalahan yang sesuai. Pembatasan berikut akan dicantumkan, jika ada yang berlaku:

  • Partisi panggilan harus memiliki hak istimewa tertentu
  • Partisi yang ditindaklanjuti harus dalam keadaan tertentu (misalnya "Aktif")

Kode Status Hypercall

Setiap hypercall didokumenkan sebagai mengembalikan nilai output yang berisi beberapa bidang. Bidang nilai status (jenis HV_STATUS) digunakan untuk menunjukkan apakah panggilan berhasil atau gagal.

Validitas Parameter Output pada Hypercalls gagal

Kecuali dinyatakan sebaliknya secara eksplisit, ketika hypercall gagal (artinya, bidang hasil dari nilai hasil hypercall berisi nilai selain HV_STATUS_SUCCESS), konten semua parameter output tidak ditentukan dan tidak boleh diperiksa oleh pemanggil. Hanya ketika hypercall berhasil, semua parameter output yang sesuai akan berisi hasil yang valid dan diharapkan.

Urutan Kondisi Kesalahan

Urutan di mana kondisi kesalahan terdeteksi dan dilaporkan oleh hypervisor tidak terdefinisi. Dengan kata lain, jika ada beberapa kesalahan, hypervisor harus memilih kondisi kesalahan mana yang akan dilaporkan. Prioritas harus diberikan kepada kode kesalahan yang menawarkan keamanan yang lebih besar, niat untuk mencegah hypervisor mengungkapkan informasi kepada penelepon yang tidak memiliki hak istimewa yang memadai. Misalnya, kode HV_STATUS_ACCESS_DENIED status adalah kode status pilihan daripada kode yang akan mengungkapkan beberapa konteks atau informasi status murni berdasarkan hak istimewa.

Kode Status Hypercall Umum

Beberapa kode hasil umum untuk semua hypercalls dan oleh karena itu tidak didokumenkan untuk setiap hypercall satu per satu. Ini termasuk yang berikut ini:

Kode status Kondisi kesalahan
HV_STATUS_SUCCESS Panggilan berhasil.
HV_STATUS_INVALID_HYPERCALL_CODE Kode hypercall tidak dikenali.
HV_STATUS_INVALID_HYPERCALL_INPUT Jumlah rep salah (misalnya, jumlah rep non-nol diteruskan ke panggilan non-rep atau jumlah rep nol diteruskan ke panggilan balasan).
Indeks mulai rep tidak kurang dari jumlah rep.
Bit yang dipesan dalam nilai input hypercall yang ditentukan adalah bukan nol.
HV_STATUS_INVALID_ALIGNMENT Pointer GPA input atau output yang ditentukan tidak selaras dengan 8 byte.
Parameter input atau output yang ditentukan mencantumkan halaman rentang.
Pointer IPK input atau output tidak berada dalam batas ruang IPK.

Kode HV_STATUS_SUCCESS pengembalian menunjukkan bahwa tidak ada kondisi kesalahan yang terdeteksi.

Melaporkan Identitas OS Tamu

OS Tamu yang berjalan dalam partisi harus mengidentifikasi dirinya ke hypervisor dengan menulis tanda tangan dan versinya ke MSR (HV_X64_MSR_GUEST_OS_ID/HvRegisterGuestOsId) sebelum dapat memanggil hypercalls. MSR ini di seluruh partisi dan dibagikan di antara semua prosesor virtual.

Nilai register ini awalnya nol.

Pada x86/x64, nilai bukan nol harus ditulis ke ID OS Tamu MSR sebelum halaman kode hypercall dapat diaktifkan (lihat Membuat Antarmuka Hypercall (x86/x64)). Jika register ini kemudian di-zero, halaman kode hypercall akan dinonaktifkan.

Pada ARM64, nilai bukan nol harus ditulis ke MSR ID OS Tamu sebelum kode hypercall dapat dipanggil. Pengecualiannya adalah hypercalls HvCallSetVpRegisters/HvCallGetVpRegisters . Silakan lihat dokumentasi masing-masing untuk informasi lebih lanjut.

#define HV_X64_MSR_GUEST_OS_ID 0x40000000
#define HvRegisterGuestOsId 0x00090002

Pada ARM64, hanya HvRegisterGuestOsId yang didukung, yang harus ditulis menggunakan hypercall HvCallSetVpRegisters pada prosesor boot.

Identitas OS Tamu untuk Sistem Operasi eksklusif

Berikut ini adalah pengodean yang direkomendasikan untuk MSR ini. Beberapa bidang mungkin tidak berlaku untuk beberapa OS Tamu.

Bit Bidang Description
15:0 Nomor Versi Build Menunjukkan nomor build OS
23:16 Versi Layanan Menunjukkan versi layanan (misalnya, nomor "paket layanan"))
31:24 Versi Minor Menunjukkan versi minor OS
39:32 Versi Utama Menunjukkan versi utama OS
47:40 OS ID Menunjukkan varian OS. Pengodean unik untuk vendor. Sistem operasi Microsoft dikodekan sebagai berikut: 0=Tidak terdefinisi, 1=MS-DOS®, 2=Windows® 3.x, 3=Windows® 9x, 4=Windows® NT (dan derivatif), 5=Windows® CE
62:48 Vendor ID Menunjukkan vendor OS Tamu. Nilai 0 dicadangkan. Lihat daftar vendor di bawah ini.
63 Jenis OS Menunjukkan jenis OS. Nilai 0 mewakili OS kepemilikan (sumber tertutup). Nilai 1 mewakili OS sumber terbuka.

Nilai vendor dialokasikan oleh Microsoft. Untuk meminta vendor baru, ajukan masalah pada repositori dokumentasi virtualisasi GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Penyedia Nilai
Microsoft 0x0001
HPE 0x0002
Blackberry 0x0003
LANCOM 0x0200

MSR Identitas OS Tamu untuk Sistem Operasi Sumber Terbuka

Pengodean berikut ditawarkan sebagai panduan untuk vendor sistem operasi sumber terbuka yang ingin sesuai dengan spesifikasi ini. Disarankan agar sistem operasi sumber terbuka mengadopsi konvensi berikut.

Bit Bidang Description
15:0 Nomor Versi Build Informasi khusus distribusi (misalnya, nomor build).
47:16 Versi Informasi versi kernel upstream.
55:48 OS ID Informasi vendor tambahan
62:56 Jenis OS Jenis OS (misalnya, Linux, FreeBSD, dll.). Lihat daftar jenis OS yang diketahui di bawah ini
63 Sumber Terbuka Nilai 1 menunjukkan OS sumber terbuka.

Nilai Jenis OS dialokasikan oleh Microsoft. Untuk meminta Jenis OS baru, ajukan masalah pada repositori dokumentasi virtualisasi GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Jenis OS Nilai
Linux 0x1
FreeBSD 0x2
Xen 0x3
Illumos 0x4

Menetapkan Antarmuka Hypercall (x86/x64)

Pada x86/x64, Hypercalls dipanggil dengan menggunakan opcode khusus. Karena opcode ini berbeda di antara implementasi virtualisasi, perlu bagi hypervisor untuk mengabstraksi perbedaan ini. Ini dilakukan melalui halaman hypercall khusus. Halaman ini disediakan oleh hypervisor dan muncul dalam ruang GPA tamu. Tamu diperlukan untuk menentukan lokasi halaman dengan memprogram MSR Guest Hypercall.

#define HV_X64_MSR_HYPERCALL 0x40000001
Bit Description Attributes
63:12 Hypercall GPFN - Menunjukkan Nomor Halaman Fisik Tamu dari halaman hypercall Baca/tulis
11:2 RsvdP. Bit harus diabaikan pada bacaan dan dipertahankan pada tulisan. Sudah Dipesan
1 Terkunci. Menunjukkan apakah MSR tidak dapat diubah. Jika diatur, MSR ini dikunci sehingga mencegah relokasi halaman hypercall. Setelah diatur, hanya reset sistem yang dapat menghapus bit. Baca/tulis
0 Aktifkan halaman hypercall Baca/tulis

Halaman hypercall dapat ditempatkan di mana saja dalam ruang GPA tamu, tetapi harus selaras dengan halaman. Jika tamu mencoba memindahkan halaman hypercall di luar batas ruang IPK, kesalahan #GP akan mengakibatkan ketika MSR ditulis.

MSR ini adalah MSR di seluruh partisi. Dengan kata lain, ini dibagikan oleh semua prosesor virtual dalam partisi. Jika satu prosesor virtual berhasil menulis ke MSR, prosesor virtual lain akan membaca nilai yang sama.

Sebelum halaman hypercall diaktifkan, OS Tamu harus melaporkan identitasnya dengan menulis tanda tangan versinya ke MSR terpisah (HV_X64_MSR_GUEST_OS_ID). Jika tidak ada identitas OS Tamu yang ditentukan, upaya untuk mengaktifkan hypercall akan gagal. Bit aktifkan akan tetap nol bahkan ketika menulis bit ke dalamnya. Selain itu, jika identitas OS Tamu dibersihkan ke nol setelah halaman hypercall diaktifkan, identitas TERSEBUT akan dinonaktifkan.

Halaman hypercall muncul sebagai "overlay" ke ruang GPA; artinya, mencakup apa pun yang dipetakan ke rentang IPK. Isinya dapat dibaca dan dapat dieksekusi oleh tamu. Upaya untuk menulis ke halaman hypercall akan menghasilkan pengecualian perlindungan (#GP). Setelah halaman hypercall diaktifkan, memanggil hypercall hanya melibatkan panggilan ke awal halaman.

Berikut ini adalah daftar terperinci dari langkah-langkah yang terlibat dalam pembuatan halaman hypercall:

  1. Tamu membaca CPUID daun 1 dan menentukan apakah hypervisor hadir dengan memeriksa bit 31 ecx register.
  2. Tamu membaca 0x40000000 daun CPUID untuk menentukan daun CPUID hypervisor maksimum (dikembalikan dalam register EAX) dan 0x40000001 daun CPUID untuk menentukan tanda tangan antarmuka (dikembalikan dalam register EAX). Ini memverifikasi bahwa nilai daun maksimum setidaknya 0x40000005 dan bahwa tanda tangan antarmuka sama dengan "Hv#1". Tanda tangan ini menyiratkan bahwa HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL dan HV_X64_MSR_VP_INDEX diimplementasikan.
  3. Tamu menulis identitas OS-nya ke dalam MSR HV_X64_MSR_GUEST_OS_ID jika register tersebut nol.
  4. Tamu membaca Hypercall MSR (HV_X64_MSR_HYPERCALL).
  5. Tamu memeriksa bit Aktifkan Halaman Hypercall. Jika diatur, antarmuka sudah aktif, dan langkah 6 dan 7 harus dihilangkan.
  6. Tamu menemukan halaman dalam ruang GPA-nya, sebaiknya yang tidak ditempati oleh RAM, MMIO, dan sebagainya. Jika halaman ditempati, tamu harus menghindari penggunaan halaman yang mendasarinya untuk tujuan lain.
  7. Tamu menulis nilai baru ke Hypercall MSR (HV_X64_MSR_HYPERCALL) yang menyertakan IPK dari langkah 6 dan mengatur bit Aktifkan Halaman Hypercall untuk mengaktifkan antarmuka.
  8. Tamu membuat pemetaan VA yang dapat dieksekusi ke GPA halaman hypercall.
  9. Tamu berkonsultasi dengan 0x40000003 daun CPUID untuk menentukan fasilitas hypervisor mana yang tersedia untuk itu. Setelah antarmuka dibuat, tamu dapat memulai hypercall. Untuk melakukannya, ini mengisi register per protokol hypercall dan mengeluarkan PANGGILAN ke awal halaman hypercall. Tamu harus mengasumsikan halaman hypercall melakukan yang setara dengan pengembalian dekat (0xC3) untuk kembali ke pemanggil. Dengan demikian, hypercall harus dipanggil dengan tumpukan yang valid.

Menetapkan Antarmuka Hypercall (ARM64)

Karena ARM64 secara asli mendukung instruksi HVC, hypervisor tidak memerlukan konfigurasi tambahan untuk mengaktifkan hypercalls.

Antarmuka Hypercall yang Diperluas

Hypercalls dengan kode panggilan di atas 0x8000 dikenal sebagai hypercalls yang diperluas. Hypercalls yang diperluas menggunakan konvensi panggilan yang sama dengan hypercalls normal dan tampak identik dari perspektif VM tamu. Hypercalls yang diperluas ditangani secara internal secara berbeda dalam hypervisor Hyper-V.

Kemampuan hypercall yang diperluas dapat dikueri dengan HvExtCallQueryCapabilities.