BerandaComputers and TechnologyPetualangan Lguest (monitor mesin virtual x86 ringan)

Petualangan Lguest (monitor mesin virtual x86 ringan)

Petualangan Tamu

Lguest adalah monitor mesin virtual x86 yang ringan untuk Linux dikembangkan dan didokumentasikan oleh Rusty Russell.
Lguest ditulis dalam gaya pemrograman terpelajar: Anda dapat mengekstrak dokumentasi dengan menjalankan membuat

, seperti yang ditunjukkan di bawah ini. 

File HTML ini telah dibuat menggunakan pohon Linux Linus versi 31 Desember 2007.
Kirim komentar tentang format HTML ke Russ Cox, rsc@swtch.com

.   Biarkan petualangan dimulai!    $ cd  linux-2.6 / driver / lguest    $ kucing BACA AKU   Selamat datang, pembaca teman, untuk tamu.  Lguest adalah sebuah petualangan, dengan Anda, pembaca, sebagai Pahlawan. Saya tidak bisa memikirkan banyak Proyek 5000-baris yang menawarkan kemampuan seperti itu dan sekilas masa depan potensi; ini adalah waktu yang menyenangkan untuk mempelajari sumbernya!  Tapi berhati-hatilah; ini adalah perjalanan yang sulit selama beberapa jam atau lebih! Dan seperti kita tahu, semua Pahlawan sejati didorong oleh Tujuan Mulia. Jadi saya menawarkan Bir (atau setara) kepada siapa pun yang saya temui yang telah menyelesaikan dokumentasi ini.  Jadi merasa nyaman dan pertahankan kecerdasan Anda (cepat dan lucu). Sepanjang jalan Anda menuju Tujuan Mulia, Anda juga akan mendapatkan wawasan yang luar biasa lguest, dan virtualisasi hypervisors dan x86 secara umum.  Misi kami ada dalam tujuh bagian: (bacaan terbaik dengan penyorotan C dihidupkan)  I) Persiapan - Di mana pahlawan potensial kita diterbangkan dengan cepat di atas lanskap untuk a rasa ruang lingkupnya. Cocok untuk pembuat kode kursi berlengan dan sejenisnya orang dengan konstitusi yang lemah.  II) Tamu - Di mana kita menemukan gumpalan kode pertama yang menggoda, dan datang ke memahami detail kehidupan kernel Tamu.  III) Pengemudi - Di mana Tamu menemukan suaranya dan menjadi berguna, dan milik kami pemahaman Tamu selesai.  IV) Peluncur - Di mana kami menelusuri kembali ke penciptaan Tamu, dan dengan demikian memulai kami pemahaman tentang Host.  V) Tuan Rumah - Dimana kita menguasai kode Host, melalui perjalanan yang panjang dan berliku. Memang di sinilah hero kita diuji di Bit of Despair.  VI) Pengalih - Dimana pemahaman kita tentang sifat Tamu dan Tuan Rumah yang saling terkait selesai.  VII) Penguasaan - Di mana pahlawan kita yang lengkap bergulat dengan Pertanyaan Hebat: "Apa selanjutnya?"  buatlah Persiapan! Rusty Russell.      $ membuat Persiapan!   [ arch/x86/lguest/boot.c ]     [ drivers/lguest/lguest_device.c ]     [ Documentation/lguest/lguest.c ]     [ drivers/lguest/lguest_user.c ]     [ drivers/lguest/core.c ]     [ drivers/lguest/hypercalls.c ]     [ drivers/lguest/segments.c ]     [ drivers/lguest/page_tables.c ]     [ drivers/lguest/interrupts_and_traps.c ]     [ drivers/lguest/x86/switcher_32.S ]       $ buat Tamu   [ arch/x86/lguest/boot.c ]     [ arch/x86/lguest/i386_head.S ]   .section .init.text, "ax", @progbits MASUK (lguest_entry)  pindah $ LHCALL_LGUEST_INIT,% eax movl $ lguest_data - __PAGE_OFFSET,% edx int $ LGUEST_TRAP_ENTRY   movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir,% esi   pindah $ 32,% ecx movl% esi,% edi addl $ ((__ HALAMAN_OFFSET>> 22) 4),% edi reputasi movsl   movl $ (init_thread_union + THREAD_SIZE),% esp   jmp lguest_init + __ PAGE_OFFSET   [ arch/x86/lguest/boot.c ]   __init batal lguest_init (batal) {  pv_info.name="lguest"; pv_info.paravirt_enabled=1; pv_info.kernel_rpl=1;     pv_irq_ops.init_IRQ=lguest_init_IRQ; pv_irq_ops.save_fl=save_fl; pv_irq_ops.restore_fl=restore_fl; pv_irq_ops.irq_disable=irq_disable; pv_irq_ops.irq_enable=irq_enable; pv_irq_ops.safe_halt=lguest_safe_halt;   pv_init_ops.memory_setup=lguest_memory_setup; pv_init_ops.patch=lguest_patch;   pv_cpu_ops.load_gdt=lguest_load_gdt; pv_cpu_ops.cpuid=lguest_cpuid; pv_cpu_ops.load_idt=lguest_load_idt; pv_cpu_ops.iret=lguest_iret; pv_cpu_ops.load_esp0=lguest_load_esp0; pv_cpu_ops.load_tr_desc=lguest_load_tr_desc; pv_cpu_ops.set_ldt=lguest_set_ldt; pv_cpu_ops.load_tls=lguest_load_tls; pv_cpu_ops.set_debugreg=lguest_set_debugreg; pv_cpu_ops.clts=lguest_clts; pv_cpu_ops.read_cr0=lguest_read_cr0; pv_cpu_ops.write_cr0=lguest_write_cr0; pv_cpu_ops.read_cr4=lguest_read_cr4; pv_cpu_ops.write_cr4=lguest_write_cr4; pv_cpu_ops.write_gdt_entry=lguest_write_gdt_entry; pv_cpu_ops.write_idt_entry=lguest_write_idt_entry; pv_cpu_ops.wbinvd=lguest_wbinvd; pv_cpu_ops.lazy_mode.enter=paravirt_enter_lazy_cpu; pv_cpu_ops.lazy_mode.leave=lguest_leave_lazy_mode;   pv_mmu_ops.write_cr3=lguest_write_cr3; pv_mmu_ops.flush_tlb_user=lguest_flush_tlb_user; pv_mmu_ops.flush_tlb_single=lguest_flush_tlb_single; pv_mmu_ops.flush_tlb_kernel=lguest_flush_tlb_kernel; pv_mmu_ops.set_pte=lguest_set_pte; pv_mmu_ops.set_pte_at=lguest_set_pte_at; pv_mmu_ops.set_pmd=lguest_set_pmd; pv_mmu_ops.read_cr2=lguest_read_cr2; pv_mmu_ops.read_cr3=lguest_read_cr3; pv_mmu_ops.lazy_mode.enter=paravirt_enter_lazy_mmu; pv_mmu_ops.lazy_mode.leave=lguest_leave_lazy_mode;  #ifdef CONFIG_X86_LOCAL_APIC  pv_apic_ops.apic_write=lguest_apic_write; pv_apic_ops.apic_write_atomic=lguest_apic_write; pv_apic_ops.apic_read=lguest_apic_read; #berakhir jika   pv_time_ops.get_wallclock=lguest_get_wallclock; pv_time_ops.time_init=lguest_time_init;     [ include/asm-x86/lguest_hcall.h ]   statis inline unsigned long hcall (panggilan panjang tanpa tanda tangan,       unsigned long arg1, unsigned long arg2, unsigned long arg3) {  asm volatile ("int $" __stringify (LGUEST_TRAP_ENTRY)  : "=a" (panggilan)  : "a" (call), "d" (arg1), "b" (arg2), "c" (arg3)  : "Penyimpanan"); panggilan balik; }    [ include/linux/lguest.h ]     [ arch/x86/lguest/boot.c ]     save_fl lama unsigned statis (void) { return lguest_data.irq_enabled; }   static void restore_fl (tanda panjang tidak bertanda) { lguest_data.irq_enabled=bendera; }   void statis irq_disable (void) { lguest_data.irq_enabled=0; }   void statis irq_enable (void) { lguest_data.irq_enabled=X86_EFLAGS_IF; }    kekosongan statis lguest_write_idt_entry (struct desc_struct dt, int entrynum, u32 rendah, u32 tinggi) {  write_dt_entry (dt, entrynum, rendah, tinggi);  hcall (LHCALL_LOAD_IDT_ENTRY, entrynum, low, high); }   kekosongan statis lguest_load_idt (const struct Xgt_desc_struct desc) { unsigned int i; struct desc_struct idt=(void  desc-> alamat;  untuk (i=0; i  ukuran + 1) / 8; i ++) hcall (LHCALL_LOAD_IDT_ENTRY, i, idt [i]. a, idt [i]. b); }   kekosongan statis lguest_load_gdt (const struct Xgt_desc_struct desc) { BUG_ON ((desc-> ukuran + 1) / 8!=GDT_ENTRIES); hcall (LHCALL_LOAD_GDT, __pa (uraian-> alamat), GDT_ENTRIES, 0); }   kekosongan statis lguest_write_gdt_entry (struct desc_struct dt, int entrynum, u32 rendah, u32 tinggi) { write_dt_entry (dt, entrynum, rendah, tinggi); hcall (LHCALL_LOAD_GDT, __pa (dt), GDT_ENTRIES, 0); }   void statis lguest_load_tls (struct thread_struct t, unsigned int cpu) {  loadegment (gs, 0); lazy_hcall (LHCALL_LOAD_TLS, __pa (& t-> tls_array), cpu, 0); }   static void lazy_hcall (panggilan panjang tanpa tanda tangan, arg1 panjang unsigned, arg2 panjang unsigned, arg3 panjang unsigned) { jika (paravirt_get_lazy_mode ()==PARAVIRT_LAZY_NONE) hcall (call, arg1, arg2, arg3); lain async_hcall (panggil, arg1, arg2, arg3); }   kekosongan statis lguest_leave_lazy_mode (batal) { paravirt_leave_lazy (paravirt_get_lazy_mode ()); hcall (LHCALL_FLUSH_ASYNC, 0, 0, 0); }   static void async_hcall (panggilan panjang unsigned, unsigned long arg1, unsigned long arg2, unsigned long arg3) {  statis unsigned int next_call; bendera panjang tak bertanda tangan;   local_irq_save (bendera); jika (lguest_data.hcall_status [next_call]!=0xFF) {  hcall (call, arg1, arg2, arg3); } lain { lguest_data.hcalls [next_call]. arg0=panggilan; lguest_data.hcalls [next_call]. arg1=arg1; lguest_data.hcalls [next_call]. arg2=arg2; lguest_data.hcalls [next_call]. arg3=arg3;  wmb (); lguest_data.hcall_status [next_call]=0; jika (++ panggilan_berikutnya==LHCALL_RING_SIZE) panggilan_berikutnya=0; } local_irq_restore (bendera); }   static void lguest_set_ldt (const void addr, entri unsigned) { }   kekosongan statis lguest_load_tr_desc (batal) { }   static void lguest_cpuid (unsigned int eax, unsigned int ebx, unsigned int ecx, unsigned int edx) { fungsi int=eax;  native_cpuid (eax, ebx, ecx, edx); saklar (fungsi) { kasus 1:  ecx &=0x00002201;  edx &=0x07808101;  edx |=0x00002000; istirahat; kasus 0x80000000:  jika  eax> 0x80000008) eax=0x80000008; istirahat; } }   current_cr0 panjang unsigned statis, current_cr3; static void lguest_write_cr0 (unsigned long val) { lazy_hcall (LHCALL_TS, val & X86_CR0_TS, 0, 0); current_cr0=val; }  statis unsigned panjang lguest_read_cr0 (void) { kembali current_cr0; }   kekosongan statis lguest_clts (batal) { lazy_hcall (LHCALL_TS, 0, 0, 0); current_cr0 &=~ X86_CR0_TS; }   statis unsigned panjang lguest_read_cr2 (void) { return lguest_data.cr2; }   void statis lguest_write_cr3 (cr3 panjang unsigned) { lazy_hcall (LHCALL_NEW_PGTABLE, cr3, 0, 0); current_cr3=cr3; }  statis unsigned panjang lguest_read_cr3 (void) { kembali current_cr3; }   statis unsigned panjang lguest_read_cr4 (void) { kembali 0; }  kekosongan statis lguest_write_cr4 (val panjang tak bertanda tangan) { }     static void lguest_set_pte_at (struct mm_struct mm, unsigned long addr, pte_t ptep, pte_t pteval) { ptep=pteval; lazy_hcall (LHCALL_SET_PTE, __pa (mm-> pgd), addr, pteval.pte_low); }   void statis lguest_set_pmd (pmd_t pmdp, pmd_t pmdval) { pmdp=pmdval; lazy_hcall (LHCALL_SET_PMD, __pa (pmdp) & PAGE_MASK, (__pa (pmdp) & (HALAMAN_SIZE-1)) / 4, 0); }   kekosongan statis lguest_set_pte (pte_t ptep, pte_t pteval) { ptep=pteval;  jika (current_cr3) lazy_hcall (LHCALL_FLUSH_TLB, 1, 0, 0); }   kekosongan statis lguest_flush_tlb_single (alamat panjang tak bertanda tangan) {  lazy_hcall (LHCALL_SET_PTE, current_cr3, addr, 0); }   kekosongan statis lguest_flush_tlb_user (batal) { lazy_hcall (LHCALL_FLUSH_TLB, 0, 0, 0); }   kekosongan statis lguest_flush_tlb_kernel (batal) { lazy_hcall (LHCALL_FLUSH_TLB, 1, 0, 0); }   static void disable_lguest_irq (unsigned int irq) { set_bit (irq, lguest_data.blocked_interrupts); }  static void enable_lguest_irq (unsigned int irq) { clear_bit (irq, lguest_data.blocked_interrupts); }   struktur statis irq_chip lguest_irq_controller={ .name="lguest", .mask=disable_lguest_irq, .mask_ack=disable_lguest_irq, .unmask=enable_lguest_irq, };   static void __init lguest_init_IRQ (batal) { unsigned int i;  untuk (i=0; i  esp0, THREAD_SIZE / PAGE_SIZE); }   static void lguest_set_debugreg (int regno, nilai panjang unsigned) {  }   void statis lguest_wbinvd (void) { }   #ifdef CONFIG_X86_LOCAL_APIC static void lguest_apic_write (reg panjang unsigned, unsigned long v) { }  statis unsigned panjang lguest_apic_read (reg panjang unsigned) { kembali 0; } #berakhir jika   kekosongan statis lguest_safe_halt (batal) { hcall (LHCALL_HALT, 0, 0, 0); }   void statis lguest_power_off (void) { hcall (LHCALL_CRASH, __pa ("Power down"), 0, 0); }   static int lguest_panic (struct notifier_block nb, unsigned long l, void p) { hcall (LHCALL_CRASH, __pa (p), 0, 0);  kembali NOTIFY_DONE; }  static struct notifier_block paniced={ .notifier_call=lguest_panic };   static __init char lguest_memory_setup (tidak berlaku) {  atomic_notifier_chain_register (& panic_notifier_list, & paniced);   add_memory_region (boot_params.e820_map [0]. addr, boot_params.e820_map [0]. ukuran, boot_params.e820_map [0]. type);   mengembalikan "LGUEST"; }   static __init int early_put_chars (u32 vtermno, const char buf, int count) { awal karakter [17]; unsigned int len ​​=hitung;   if (len> sizeof (scratch) - 1) len=sizeof (awal) - 1; awal [len]=' 0'; memcpy (awal, buf, len); hcall (LHCALL_NOTIFY, __pa (awal), 0, 0);   kembali len; }   [ arch/x86/lguest/i386_head.S ]   MASUK (lguest_iret) pushl% eax movl 12 (% esp),% eax lguest_noirq_start:  movl% eax,% ss: lguest_data + LGUEST_DATA_irq_enabled popl% eax iret lguest_noirq_end:   [ arch/x86/lguest/boot.c ]     [ arch/x86/lguest/i386_head.S ]   .teks #define LGUEST_PATCH (nama, insns ...)  lgstart _ ## name: insns; lgend _ ## nama :;  .globl lgstart _ ## name; .globl lgend _ ## name  LGUEST_PATCH (cli, movl $ 0, lguest_data + LGUEST_DATA_irq_enabled) LGUEST_PATCH (sti, movl $ X86_EFLAGS_IF, lguest_data + LGUEST_DATA_irq_enabled) LGUEST_PATCH (popf, movl% eax, lguest_data + LGUEST_DATA_irq_enabled) LGUEST_PATCH (pushf, movl lguest_data + LGUEST_DATA_irq_enabled,% eax)    [ arch/x86/lguest/boot.c ]   static const struct lguest_insns { const char mulai, akhir; } lguest_insns []={ [PARAVIRT_PATCH(pv_irq_ops.irq_disable)]={lgstart_cli, lgend_cli}, [PARAVIRT_PATCH(pv_irq_ops.irq_enable)]={lgstart_sti, lgend_sti}, [PARAVIRT_PATCH(pv_irq_ops.restore_fl)]={lgstart_popf, lgend_popf}, [PARAVIRT_PATCH(pv_irq_ops.save_fl)]={lgstart_pushf, lgend_pushf}, };   statis unsigned lguest_patch (tipe u8, clobber u16, void ibuf, addr panjang unsigned, unsigned len) { unsigned int insn_len;   if (type>=ARRAY_SIZE (lguest_insns) ||! lguest_insns [type]. mulai) return paravirt_patch_default (type, clobber, ibuf, addr, len);  insn_len=lguest_insns [type]. end - lguest_insns [type].Mulailah;   jika (len   $ buat Driver   [ include/linux/lguest_launcher.h ]   struct lguest_device_desc {  jenis __u8;  __u8 config_len;  status __u8; __u8 config [0]; };   [ drivers/lguest/lguest_device.c ]   struct lguest_device { struct virtio_device vdev;   struct lguest_device_desc desc; };   # Tentukan to_lgdev (vdev) container_of (vdev, struct lguest_device, vdev)   static int __init lguest_devices_init (batal) { if (strcmp (pv_info.name, "lguest")!=0) kembali 0;  jika (device_register (& lguest_root)!=0) panic ("Tidak dapat mendaftarkan lguest root");   lguest_devices=lguest_map (max_pfn  config_len) { d=lguest_devices + i;   jika (d-> ketik==0) istirahat;  add_lguest_device (d); } }   statis void add_lguest_device (struct lguest_device_desc d) { struct lguest_device ldev;   ldev=kzalloc (sizeof  ldev), GFP_KERNEL); if (! ldev) { printk (KERN_EMERG "Tidak dapat mengalokasikan lguest dev% u  n", dev_index ++); kembali; }   ldev-> vdev.dev.parent=& lguest_root;  ldev-> vdev.index=dev_index ++;  ldev-> vdev.id.device=d-> ketik;  ldev-> vdev.config=& lguest_config_ops;  ldev-> desc=d;   if (register_virtio_device (& ldev-> vdev)!=0) { printk (KERN_ERR "Gagal mendaftarkan perangkat lguest% u  n", ldev-> vdev.index); kfree (ldev); } }     #define FHDR_LEN 2   void statis lg_find (struct virtio_device vdev, tipe u8, unsigned int len) { struct lguest_device_desc desc=to_lgdev (vdev) -> desc; int i;  untuk (i=0; i  config_len; i +=FHDR_LEN + desc-> config [i+1]) { if (desc-> config [i]==type) {  desc-> config [i] |=0x80;  len=desc-> config [i+1];  kembali desc-> config + i; } }   kembali NULL; }   void statis lg_get (struct virtio_device vdev, void token, void buf, unsigned len) {  BUG_ON (len> ((u8  token) [1]); memcpy (buf, token + FHDR_LEN, len); }   void statis lg_set (struct virtio_device vdev, void token, const void buf, unsigned len) { BUG_ON (len> ((u8  token) [1]); memcpy (token + FHDR_LEN, buf, len); }   statis u8 lg_get_status (struct virtio_device vdev) { kembali ke_lgdev (vdev) -> desc-> status; }  void statis lg_set_status (struct virtio_device vdev, status u8) { to_lgdev (vdev) -> desc-> status=status; }     [ include/linux/lguest_launcher.h ]   struct lguest_vqconfig {  __u16 num;  __u16 irq;  __u32 pfn; };    [ drivers/lguest/lguest_device.c ]   struct lguest_vq_info {  struct lguest_vqconfig config;   halaman kosong *; };   void statis lg_notify (struct virtqueue vq) {  struct lguest_vq_info lvq=vq-> priv;  hcall (LHCALL_NOTIFY, lvq-> config.pfn  config-> temukan (vdev, VIRTIO_CONFIG_F_VIRTQUEUE, & len); if (! token) kembali ERR_PTR (-ENOENT);  lvq=kmalloc (ukuran  lvq), GFP_KERNEL); if (! lvq) kembali ERR_PTR (-ENOMEM);   if (len!=sizeof (lvq-> config)) { dev_err (& vdev-> dev, "Config virtio tak terduga len% u  n", len); err=-EIO; buka free_lvq; }  vdev-> config-> get (vdev, token, & lvq-> config, sizeof (lvq-> config));   lvq-> halaman=lguest_map ((panjang unsigned) lvq-> config.pfn  config.num, UKURAN HALAMAN), UKURAN HALAMAN)); if (! lvq-> halaman) { err=-ENOMEM; buka free_lvq; }   vq=vring_new_virtqueue (lvq-> config.num, vdev, lvq-> halaman, lg_notify, callback); if (! vq) { err=-ENOMEM; goto unmap; }    err=request_irq (lvq-> config.irq, vring_interrupt, IRQF_SHARED, vdev-> dev.bus_id, vq); jika (err) pergi ke destroy_vring;   vq-> priv=lvq; kembali vq;  destroy_vring: vring_del_virtqueue (vq); batalkan peta: lguest_unmap (lvq-> halaman); free_lvq: kfree (lvq); kembali ERR_PTR (err); }        $ buat Peluncur   [ drivers/lguest/lguest_user.c ]   struktur statis file_operations lguest_fops={ .owner=THIS_MODULE, .release=tutup, .write=tulis, .read=baca, };   kesalahan perangkat struktur statis lguest_dev={ .minor=MISC_DYNAMIC_MINOR, .name="lguest", .fops=& lguest_fops, };  int __init lguest_device_init (batal) { kembalikan misc_register (& lguest_dev); }  void __exit lguest_device_remove (batal) { misc_deregister (& lguest_dev); }   statis ssize_t tulis (file struct file, const char __user dalam, size_t size, loff_t off) {  struct lguest lg=file-> private_data; const unsigned long __user input=(const unsigned long __user  in; permintaan panjang unsigned;  if (get_user (req, input)!=0) kembali -EFAULT; masukan ++;   if (req!=LHREQ_INITIALIZE &&! lg) kembali -EINVAL;   jika (lg && lg-> mati) kembali -ENOENT;   if (lg && current!=lg-> tsk && req!=LHREQ_BREAK) kembali -EPERM;  switch (req) { kasus LHREQ_INITIALIZE: kembali menginisialisasi (file, input); kasus LHREQ_IRQ: return user_send_irq (lg, masukan); kasus LHREQ_BREAK: return break_guest_out (lg, masukan); default: kembali -EINVAL; } }   static int inisialisasi (struct file file, const unsigned long __user input) {  struct lguest lg; int err; args panjang unsigned [4];   mutex_lock (& ​​lguest_lock);  if (file-> private_data) { err=-EBUSY; buka kunci; }  if (copy_from_user (args, input, sizeof (args))!=0) { err=-EFAULT; buka kunci; }  lg=kzalloc (ukuran  lg), GFP_KERNEL); if (! lg) { err=-ENOMEM; buka kunci; }   lg-> mem_base=(void __user  (long) args [0]; lg-> pfn_limit=args [1];   lg-> regs_page=get_zeroed_page (GFP_KERNEL); if (! lg-> regs_page) { err=-ENOMEM; goto release_guest; }  lg-> regs=(void  lg-> regs_page + PAGE_SIZE - sizeof  lg-> regs);   err=init_guest_pagetable (lg, args [2]); jika (err) buka free_regs;   lguest_arch_setup_regs (lg, args [3]);   init_clockdev (lg);   lg-> tsk=arus;  lg-> mm=get_task_mm (lg-> tsk);   init_waitqueue_head (& lg-> break_wq);   lg-> last_pages=NULL;   file-> private_data=lg;  mutex_unlock (& ​​lguest_lock);   return sizeof (args);  free_regs: free_page (lg-> regs_page); release_guest: kfree (lg); membuka kunci: mutex_unlock (& ​​lguest_lock); kembali salah; }   [ drivers/lguest/x86/core.c ]   void lguest_arch_setup_regs (struct lguest lg, unsigned long start) { struct lguest_regs regs=lg-> regs;   regs-> ds=regs-> es=regs-> ss=__KERNEL_DS | GUEST_PL; regs-> cs=__KERNEL_CS | GUEST_PL;   regs-> eflags=X86_EFLAGS_IF | 0x2;   regs-> eip=mulai;     setup_guest_gdt (lg); }   [ drivers/lguest/lg.h ]   # Tentukan kill_guest (lg, fmt ...)  lakukan { if (! (lg) -> dead) { (lg) -> mati=kasprintf (GFP_ATOMIC, fmt);  if (! (lg) -> dead)  (lg) -> mati=ERR_PTR (-ENOMEM);  }  } sementara (0)    [ drivers/lguest/lguest_user.c ]   statis ssize_t baca (file struct file, char __user pengguna, ukuran_ukuran, loff_t o) { struct lguest lg=file-> private_data;   if (! lg) kembali -EINVAL;   if (saat ini!=lg-> tsk) kembali -EPERM;   jika (lg-> mati) { size_t len;   jika (IS_ERR (lg-> mati)) kembali PTR_ERR (lg-> mati);   len=min (ukuran, strlen (lg-> mati) +1); if (copy_to_user (user, lg-> dead, len)!=0) kembali -EFAULT; kembali len; }   if (lg-> pending_notify) lg-> pending_notify=0;   return run_guest (lg, (unsigned long __user  user); }   static int user_send_irq (struct lguest lg, const unsigned long __user input) { irq panjang unsigned;  if (get_user (irq, input)!=0) kembali -EFAULT; if (irq>=LGUEST_IRQS) kembali -EINVAL;  set_bit (irq, lg-> irqs_pending); kembali 0; }   static int break_guest_out (struct lguest lg, const unsigned long __user input) { unsigned lama;   if (get_user (on, input)!=0) kembali -EFAULT;  jika (hidup) { lg-> break_out=1;  wake_up_process (lg-> tsk);  kembali wait_event_interruptible (lg-> break_wq,! lg-> break_out); } lain { lg-> break_out=0; wake_up (& lg-> break_wq); kembali 0; } }     [ Documentation/lguest/lguest.c ]   static void from_guest_phys (addr panjang unsigned) { kembali guest_base + addr; }  statis unsigned panjang to_guest_phys (const void addr) { kembali (addr - guest_base); }   int utama (int argc, char argv []) {  unsigned long mem=0, pgdir, start, initrd_size=0;  int i, c, lguest_fd;  struct boot_params boot;  const char initrd_name=NULL;   FD_ZERO (& devices.infds); perangkat.max_infd=-1; perangkat.lastdev=& perangkat.dev; devices.next_irq=1;   untuk (i=1; i  argc) pemakaian();  verbose ("Basis tamu di% p  n", basis_ tamu);   setup_console ();   mulai=load_kernel (open_or_die (argv [optind+1], O_RDONLY));   boot=from_guest_phys (0);   if (initrd_name) { initrd_size=load_initrd (initrd_name, mem);  boot-> hdr.ramdisk_image=mem - initrd_size; boot-> hdr.ramdisk_size=initrd_size;  boot-> hdr.type_of_loader=0xFF; }   pgdir=setup_pagetables (mem, initrd_size);   boot-> e820_entries=1; boot-> e820_map [0]=((struct e820entry) {0, mem, E820_RAM});  boot-> hdr.cmd_line_ptr=to_guest_phys (boot + 1);  concat ((char  (boot + 1), argv + optind + 2);   boot-> hdr.version=0x207;   boot-> hdr.hardware_subarch=1;   boot-> hdr.loadflags |=KEEP_SEGMENTS;   lguest_fd=tell_kernel (pgdir, mulai);   waker_fd=setup_waker (lguest_fd);   run_guest (lguest_fd); }    typedef unsigned long long u64; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8;    bool verbose statis; #define verbose (args ...)  do {if (verbose) printf (args); } sementara (0)    static int open_or_die (nama karakter const, flag int) { int fd=open (nama, bendera); jika (fd  guest_max) errx (1, "Tidak cukup memori untuk perangkat"); kembali addr; }   static void map_at (int fd, void addr, offset panjang unsigned, long len unsigned) { ssize_t r;   jika (mmap (addr, len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset)!=MAP_FAILED) kembali;   r=pread (fd, addr, len, offset); jika (r!=len) err (1, "Pembacaan offset% lu len% lu memberikan% zi", offset, len, r); }   map_elf panjang statis unsigned (int elf_fd, const Elf32_Ehdr ehdr) { Elf32_Phdr phdr [ehdr->e_phnum]; unsigned int i;   if (ehdr-> e_type!=ET_EXEC || ehdr-> e_machine!=EM_386 || ehdr-> e_phentsize!=sizeof (Elf32_Phdr) || ehdr-> e_phnum  e_phnum> 65536U / sizeof (Elf32_Phdr)) errx (1, "Bentuk header elf salah");     jika (lseek (elf_fd, ehdr-> e_phoff, SEEK_SET)  e_phnum; i ++) {  jika (phdr [i]. p_type!=PT_LOAD) terus;  verbose ("Bagian% i: ukuran% i addr% p  n", i, phdr [i]. p_memsz, (void  phdr [i]. p_paddr);   map_at (elf_fd, from_guest_phys (phdr [i]. p_paddr), phdr [i]. p_offset, phdr [i]. p_filesz); }   kembali ehdr-> e_entry; }   load_kernel panjang statis unsigned (int fd) { Elf32_Ehdr hdr;   if (baca (fd, & hdr, sizeof (hdr))!=sizeof (hdr)) err (1, "Membaca kernel");   jika (memcmp (hdr.e_ident, ELFMAG, SELFMAG)==0) mengembalikan map_elf (fd, & hdr);   kembali load_bzimage (fd); }   page_align panjang statis inline unsigned (unsigned long addr) {  return ((addr + getpagesize () - 1) & ~ (getpagesize () - 1)); }   load_bzimage panjang statis unsigned (int fd) { struct boot_params boot; int r;  batal p=from_guest_phys (0x100000);   lseek (fd, 0, SEEK_SET); read (fd, & boot, sizeof (boot));   if (memcmp (& boot.hdr.header, "HdrS", 4)!=0) errx (1, "Bagiku ini tidak terlihat seperti gambar bz");   lseek (fd, (boot.hdr.setup_sects + 1) 512, SEEK_SET);   sementara ((r=read (fd, p, 65536))> 0) p +=r;   return boot.hdr.code32_start; }   load_initrd panjang unsigned statis (nama char const, mem panjang unsigned) { int ifd; struct stat st; len panjang tanpa tanda tangan;  ifd=open_or_die (nama, O_RDONLY);  jika (fstat (ifd, & st)  getpagesize ()) errx (1, "Terlalu banyak perangkat");   d=(void  devices.descpage + devices.desc_used; d-> type=type; perangkat.desc_used +=sizeof  d);  kembali d; }   static void add_desc_field (perangkat struct dev, tipe u8, u8 len, const void c) {  menegaskan (devices.descpage + devices.desc_used==(u8  (dev-> desc + 1) + dev-> desc-> config_len);   if (devices.desc_used + 2 + len> getpagesize ()) errx (1, "Terlalu banyak perangkat");   devices.descpage [devices.desc_used++]=ketik; devices.descpage [devices.desc_used++]=len; memcpy (devices.descpage + devices.desc_used, c, len); perangkat.desc_used +=len;   dev-> desc-> config_len +=2 + len; }   static void add_virtqueue (perangkat struct dev, unsigned int num_descs, void  handle_output) (int fd, struct virtqueue me)) { halaman int unsigned; struct virtqueue i, vq=malloc (sizeof  vq)); batal p;   halaman=(vring_size (num_descs, getpagesize ()) + getpagesize () - 1) / getpagesize (); p=get_pages (halaman);   vq-> berikutnya=NULL; vq-> last_avail_idx=0; vq-> dev=dev;   vq-> config.num=num_descs; vq-> config.irq=devices.next_irq ++; vq-> config.pfn=to_guest_phys (p) / getpagesize ();   vring_init (& vq-> vring, num_descs, p, getpagesize ());   add_desc_field (dev, VIRTIO_CONFIG_F_VIRTQUEUE, sizeof (vq-> config), & vq-> config);   untuk (i=& dev-> vq; i; i=&  i) -> next); i=vq;   vq-> handle_output=handle_output;   if (! handle_output) vq-> vring.used-> flags=VRING_USED_F_NO_NOTIFY; }   static struct device new_device (nama char const, tipe u16, int fd, bool  handle_input) (int, struct device ) { perangkat struct dev=malloc (sizeof  dev));   devices.lastdev=dev; dev-> selanjutnya=NULL; devices.lastdev=& dev-> selanjutnya;   dev-> fd=fd;  if (handle_input) add_device_fd (dev-> fd); dev-> desc=new_dev_desc (tipe); dev-> handle_input=handle_input; dev-> nama=nama; dev-> vq=NULL; return dev; }   statis void setup_console (void) { perangkat struct dev;   jika (tcgetattr (STDIN_FILENO, & orig_term)==0) { istilah struct termios=orig_term;  term.c_lflag &=~ (ISIG | ICANON | ECHO); tcsetattr (STDIN_FILENO, TCSANOW, & istilah);  atexit (restore_term); }  dev=new_device ("konsol", VIRTIO_ID_CONSOLE, STDIN_FILENO, handle_console_input);  dev-> priv=malloc (sizeof (struct console_abort)); ((struct console_abort  dev-> priv) -> count=0;   add_virtqueue (dev, VIRTQUEUE_NUM, enable_fd); add_virtqueue (dev, VIRTQUEUE_NUM, handle_console_output);  verbose ("device% u: console  n", devices.device_num ++); }    static void setup_tun_net (const char arg) { perangkat struct dev; struct ifreq ifr; int netfd, ipfd; u32 ip; const char br_name=NULL; u8 hwaddr [6];   netfd=open_or_die ("/ dev / net / tun", O_RDWR); memset (& ifr, 0, sizeof (ifr)); ifr.ifr_flags=IFF_TAP | IFF_NO_PI; strcpy (ifr.ifr_name, "tap% d"); if (ioctl (netfd, TUNSETIFF, & ifr)!=0) err (1, "configuring / dev / net / tun");  ioctl (netfd, TUNSETNOCSUM, 1);   dev=perangkat_baru ("net", VIRTIO_ID_NET, netfd, handle_tun_input);   add_virtqueue (dev, VIRTQUEUE_NUM, enable_fd); add_virtqueue (dev, VIRTQUEUE_NUM, handle_net_output);   ipfd=soket (PF_INET, SOCK_DGRAM, IPPROTO_IP); jika (ipfd > 24), (u8) (ip>> 16), (u8) (ip>> 8), (u8) ip); jika (br_name) verbose ("dilampirkan ke jembatan:% s  n", br_name); }     struct vblk_info {  off64_t len;   int fd;   pipa kerja int [2];   int done_fd; };    static void setup_block_file (nama file const char  { int p [2]; perangkat struct dev; struct vblk_info vblk; batal tumpukan; topi u64; unsigned int val;   pipa (p);   dev=new_device ("block", VIRTIO_ID_BLOCK, p [0], handle_io_finish);   add_virtqueue (dev, VIRTQUEUE_NUM, handle_virtblk_output);   vblk=dev-> priv=malloc (sizeof  vblk));   vblk-> fd=open_or_die (nama file, O_RDWR | O_LARGEFILE); vblk-> len=lseek64 (vblk-> fd, 0, SEEK_END);   cap=cpu_to_le64 (vblk-> len / 512); add_desc_field (dev, VIRTIO_CONFIG_BLK_F_CAPACITY, sizeof (cap), & cap);   val=cpu_to_le32 (VIRTQUEUE_NUM - 2); add_desc_field (dev, VIRTIO_CONFIG_BLK_F_SEG_MAX, sizeof (val), & val);   vblk-> done_fd=p [1];   pipa (vblk-> pipa kerja);   tumpukan=malloc (32.768); if (clone (io_thread, stack + 32768, CLONE_VM, dev)==-1) err (1, "Membuat klon");   tutup (vblk-> done_fd); tutup (vblk-> workpipe [0]);  verbose ("perangkat% u: virtblock% llu sektor  n", devices.device_num, cap); }    static void wake_parent (int pipefd, int lguest_fd) {  add_device_fd (pipefd);  untuk (;;) { fd_set rfds=devices.infds; argumen panjang tak bertanda tangan []={LHREQ_BREAK, 1};   pilih (devices.max_infd + 1, & rfds, NULL, NULL, NULL);  if (FD_ISSET (pipefd, & rfds)) { int fd;  if (baca (pipefd, & fd, sizeof (fd))==0) keluar (0);  jika (fd>=0) FD_SET (fd, & devices.infds); lain FD_CLR (-fd - 1, & devices.infds); } lain tulis (lguest_fd, args, sizeof (args)); } }   static int setup_waker (int lguest_fd) { int pipefd [2], anak;   pipa (pipefd); anak=garpu (); jika (anak==-1) err (1, "forking");  jika (anak==0) {  tutup (pipefd [1]); wake_parent (pipefd [0], lguest_fd); }  tutup (pipefd [0]);   kembali pipefd [1]; }   static void _check_pointer (addr panjang unsigned, ukuran int unsigned, baris int unsigned) {  if (addr>=guest_limit || addr + size>=guest_limit) errx (1, "% s:% i: Alamat tidak valid% # lx", __FILE__, baris, addr);  kembali from_guest_phys (addr); }  #define check_pointer (addr, size) _check_pointer (addr, size, __LINE__)   next_desc unsigned statis (struct virtqueue vq, unsigned int i) { unsigned int next;   if (! (vq-> vring.desc [i]. flag & VRING_DESC_F_NEXT)) kembali vq-> vring.num;   next=vq-> vring.desc [i]. next;  wmb ();  if (selanjutnya>=vq-> vring.num) errx (1, "Desc next is% u", next);  kembali berikutnya; }   get_vq_desc unsigned statis (struct virtqueue vq, struct iovec iov [], unsigned int out_num, unsigned int in_num) { unsigned int i, head;   jika ((u16) (vq-> vring.avail-> idx - vq-> last_avail_idx)> vq-> vring.num) errx (1, "Tamu memindahkan indeks bekas dari% u ke% u", vq-> last_avail_idx, vq-> vring.avail-> idx);   jika (vq-> vring.avail-> idx==vq-> last_avail_idx) kembali vq-> vring.num;   head=vq-> vring.avail-> ring [vq->last_avail_idx++ % vq->vring.num];   if (head>=vq-> vring.num) errx (1, "Tamu mengatakan indeks% u tersedia", kepala);   out_num=in_num=0;  i=kepala; lakukan {  iov [*out_num + *in_num]. iov_len=vq-> vring .desc [i]. len; iov [*out_num + *in_num]. iov_base=check_pointer (vq-> vring.desc [i]. addr, vq-> vring.desc [i]. len);  if (vq-> vring.desc [i]. flag & VRING_DESC_F_WRITE)  in_num) ++; lain {  jika  in_num) errx (1, "Descriptor memiliki setelah in");  out_num) ++; }   jika  out_num + in_num> vq-> vring.num) errx (1, "Deskriptor melingkar"); } sementara ((i=next_desc (vq, i))!=vq-> vring.num);  kembali kepala; }   static void add_used (struct virtqueue vq, unsigned int head, int len) { struct vring_used_elem digunakan;   used=& vq-> vring.used-> ring [vq->vring.used->idx % vq->vring.num]; bekas-> id=kepala; bekas-> len=len;  wmb (); vq-> vring.used-> idx ++; }   static void trigger_irq (int fd, struct virtqueue vq) { buf panjang tak bertanda tangan []={LHREQ_IRQ, vq-> config.irq};   if (vq-> vring.avail-> flags & VRING_AVAIL_F_NO_INTERRUPT) kembali;   if (tulis (fd, buf, sizeof (buf))!=0) err (1, "Memicu irq% i", vq-> config.irq); }   static void add_used_and_trigger (int fd, struct virtqueue vq, kepala int unsigned, int len) { add_used (vq, head, len); trigger_irq (fd, vq); }   struktur statis termios orig_term; static void restore_term (void) { tcsetattr (STDIN_FILENO, TCSANOW, & orig_term); }   struct console_abort {  hitungan int;  struct timeval mulai; };   static bool handle_console_input (int fd, struct device dev) { int len; kepala int unsigned, in_num, out_num; struct iovec iov [dev->vq->vring.num]; struct console_abort abort=dev-> priv;   head=get_vq_desc (dev-> vq, iov, & out_num, & in_num);   if (head==dev-> vq-> vring.num) return false;  jika (out_num) errx (1, "Output buffer di konsol dalam antrian?");   len=readv (dev-> fd, iov, in_num); jika (len  vq-> handle_output=NULL;  return false; }   add_used_and_trigger (fd, dev-> vq, head, len);   jika (len==1 && ((char  iov [0]. iov_base) [0]==3) { if (! abort-> count ++) gettimeofday (& abort-> start, NULL); lain jika (batalkan-> hitung==3) { struct timeval sekarang; gettimeofday (& now, NULL); jika (now.tv_sec [%02x %02x]  start.tv_sec + 1) { argumen panjang tak bertanda tangan []={LHREQ_BREAK, 0};  tutup (waker_fd);  tulis (fd, args, sizeof (args)); keluar (2); } batalkan-> hitung=0; } } lain  batalkan-> hitung=0;   kembali benar; }   void statis handle_console_output (int fd, struct virtqueue vq) { kepala int unsigned, keluar, masuk; int len; struct iovec iov [vq->vring.num];   while ((head=get_vq_desc (vq, iov, & out, & in))!=vq-> vring.num) { jika (dalam) errx (1, "Input buffer dalam antrian output?"); len=writev (STDOUT_FILENO, iov, out); add_used_and_trigger (fd, vq, head, len); } }   kekosongan statis handle_net_output (int fd, struct virtqueue vq) { kepala int unsigned, keluar, masuk; int len; struct iovec iov [vq->vring.num];   while ((head=get_vq_desc (vq, iov, & out, & in))!=vq-> vring.num) { jika (dalam) errx (1, "Input buffer dalam antrian output?");  (batal) konversi (& iov [0], struct virtio_net_hdr); len=writev (vq-> dev-> fd, iov + 1, out-1); add_used_and_trigger (fd, vq, head, len); } }   static bool handle_tun_input (int fd, struct device dev) { kepala int unsigned, in_num, out_num; int len; struct iovec iov [dev->vq->vring.num]; struct virtio_net_hdr hdr;   head=get_vq_desc (dev-> vq, iov, & out_num, & in_num); if (head==dev-> vq-> vring.num) {   if (dev-> desc-> status & VIRTIO_CONFIG_S_DRIVER_OK) warn ("network: no dma buffer!");  return false; } lain jika (out_num) errx (1, "Output buffer dalam antrian penerimaan jaringan?");   hdr=konversi (& iov [0], struct virtio_net_hdr); hdr-> bendera=0; hdr-> gso_type=VIRTIO_NET_HDR_GSO_NONE;   len=readv (dev-> fd, iov + 1, in_num-1); jika (len  vq, head, sizeof  hdr) + len);  verbose ("tun input paket len% i [*out_num + *in_num]  (% s)  n ", len, ((u8  iov [1]. iov_base) [0], ((u8  iov ]. iov_base) [1], head!=dev-> vq-> vring.num? "dikirim": "dibuang");   kembali benar; }   static bool service_io (perangkat struct dev) { struct vblk_info vblk=dev-> priv; kepala int unsigned, out_num, in_num, wlen; int ret; struct virtio_blk_inhdr di; struct virtio_blk_outhdr keluar; struct iovec iov [dev->vq->vring.num]; off64_t mati;   head=get_vq_desc (dev-> vq, iov, & out_num, & in_num); if (head==dev-> vq-> vring.num) return false;   jika (out_num==0 || in_num==0) errx (1, "Keutamaan buruk cmd% u out=% u in=% u", head, out_num, in_num);  out=convert (& iov [0], struct virtio_blk_outhdr); in=mengkonversi (& iov [%02x %02x] , struct virtio_blk_inhdr); off=out-> sektor 512;   jika (keluar-> ketik & VIRTIO_BLK_T_BARRIER) fdatasync (vblk-> fd);   jika (keluar-> ketik & VIRTIO_BLK_T_SCSI_CMD) { fprintf (stderr, "Perintah Scsi tidak didukung  n"); dalam-> status=VIRTIO_BLK_S_UNSUPP; wlen=sizeof  dalam); } lain jika (keluar-> ketik & VIRTIO_BLK_T_OUT) {    if (lseek64 (vblk-> fd, off, SEEK_SET)!=off) err (1, "Bad seek to sector% llu", out-> sector);  ret=writev (vblk-> fd, iov + 1, out_num-1); verbose ("MENULIS ke sektor% llu:% i  n", di luar-> sektor, ret);   if (ret> 0 && off + ret> vblk-> len) {  ftruncate64 (vblk-> fd, vblk-> len);  errx (1, "Tulis akhir% llu +% u", nonaktif, ret); } wlen=sizeof  dalam); di-> status=(ret>=0? VIRTIO_BLK_S_OK: VIRTIO_BLK_S_IOERR); } lain {    if (lseek64 (vblk-> fd, off, SEEK_SET)!=off) err (1, "Bad seek to sector% llu", out-> sector);  ret=readv (vblk-> fd, iov + 1, in_num-1); verbose ("BACA dari sektor% llu:% i  n", di luar-> sektor, ret); if (ret>=0) { wlen=sizeof  in) + ret; dalam-> status=VIRTIO_BLK_S_OK; } lain { wlen=sizeof  dalam); dalam-> status=VIRTIO_BLK_S_IOERR; } }   add_used (dev-> vq, head, wlen); kembali benar; }   static int io_thread (void _dev) { perangkat struct dev=_dev; struct vblk_info vblk=dev-> priv; char c;   tutup (vblk-> workpipe [1]);  dekat (dev-> fd);   while (baca (vblk-> workpipe [0], & c, 1)==1) {  sementara (service_io (dev)) tulis (vblk-> done_fd, & c, 1); } kembali 0; }   static bool handle_io_finish (int fd, struct device dev) { char c;   if (baca (dev-> fd, & c, 1)!=1) keluar (1);   trigger_irq (fd, dev-> vq); kembali benar; }   static void handle_virtblk_output (int fd, struct virtqueue vq) { struct vblk_info vblk=vq-> dev-> priv; char c=0;   if (tulis (vblk-> workpipe [1], & c, 1)!=1)  keluar (1); }   static void enable_fd (int fd, struct virtqueue vq) { add_device_fd (vq-> dev-> fd);  tulis (waker_fd, & vq-> dev-> fd, sizeof (vq-> dev-> fd)); }   static void handle_output (int fd, unsigned long addr) { perangkat struct i; struct virtqueue vq;   untuk (i=devices.dev; i; i=i-> next) { untuk (vq=i-> vq; vq; vq=vq-> selanjutnya) { if (vq-> config.pfn==addr / getpagesize () && vq-> handle_output) { verbose ("Output ke% s  n", vq-> dev-> name); vq-> handle_output (fd, vq); kembali; } } }   if (addr>=guest_limit) errx (1, "PEMBERITAHUAN Buruk% # lx", addr);  tulis (STDOUT_FILENO, from_guest_phys (addr), strnlen (from_guest_phys (addr), guest_limit - addr)); }   kekosongan handle_input statis (int fd) {  struct timeval poll={.tv_sec=0, .tv_usec=0};  untuk (;;) { perangkat struct i; fd_set fds=devices.infds;   if (pilih (devices.max_infd + 1, & fds, NULL, NULL, & poll)==0) istirahat;   untuk (i=devices.dev; i; i=i-> next) { if (i-> handle_input && FD_ISSET (i-> fd, & fds)) { int dev_fd; if (i-> handle_input (fd, i)) terus;   FD_CLR (i-> fd, & devices.infds);  dev_fd=-i-> fd - 1; tulis (waker_fd, & dev_fd, sizeof (dev_fd)); } } } }   static void __attribute __ ((noreturn)) run_guest (int lguest_fd) { untuk (;;) { argumen panjang tak bertanda tangan []={LHREQ_BREAK, 0}; notify_addr panjang unsigned; int readval;   readval=read (lguest_fd, & notify_addr, sizeof (notify_addr));   if (readval==sizeof (notify_addr)) { verbose ("Beri tahu tentang alamat% # lx  n", notify_addr); handle_output (lguest_fd, notify_addr); terus;  } lain jika (errno==ENOENT) { alasan karakter [1024]={0}; read (lguest_fd, reason, sizeof (reason) -1); errx (1, "% s", alasan);  } lain jika (errno!=EAGAIN) err (1, "Tamu berjalan gagal");   handle_input (lguest_fd); if (tulis (lguest_fd, args, sizeof (args))    $ membuat Host   [ drivers/lguest/core.c ]   static int __init init (void) { int err;   jika (paravirt_enabled ()) { printk ("Tamu takut% s  n", pv_info.name); kembali -EPERM; }   err=map_switcher (); jika (err) keluar;   err=init_pagetables (switcher_page, SHARED_SWITCHER_PAGES); jika (err) goto unmap;   err=init_interrupts (); jika (err) buka free_pgtables;   err=lguest_device_init (); jika (err) buka free_interrupts;   lguest_arch_host_init ();   kembali 0;  free_interrupts: free_interrupts (); free_pgtables: free_pagetables (); batalkan peta: unmap_switcher (); di luar: kembali salah; }   static void __exit fini (void) { lguest_device_remove (); free_interrupts (); free_pagetables (); unmap_switcher ();  lguest_arch_host_fini (); }    static __init int map_switcher (void) { int i, err; halaman struct pagep;     switcher_page=kmalloc (sizeof (switcher_page [0]) TOTAL_SWITCHER_PAGES, GFP_KERNEL); if (! switcher_page) { err=-ENOMEM; keluar; }   untuk (i=0; i  addr, start_switcher_text, end_switcher_text - start_switcher_text);  printk (KERN_INFO "lguest: pengalih yang dipetakan di% p  n", switcher_vma-> addr);  kembali 0;  free_vma: vunmap (switcher_vma-> addr); free_pages: i=TOTAL_SWITCHER_PAGES; free_some_pages: untuk (--i; i>=0; i--) __free_pages (switcher_page [i], 0); kfree (switcher_page); di luar: kembali salah; }    [ drivers/lguest/x86/core.c ]   void __init lguest_arch_host_init (batal) { int i;   untuk (i=0; i  status;   state-> host_gdt_desc.size=GDT_SIZE-1; state-> host_gdt_desc.address=(panjang) get_cpu_gdt_table (i);   store_idt (& state-> host_idt_desc);   state-> guest_idt_desc.size=sizeof (state-> guest_idt) -1; state-> guest_idt_desc.address=(panjang) & state-> guest_idt; state-> guest_gdt_desc.size=sizeof (state-> guest_gdt) -1; state-> guest_gdt_desc.address=(panjang) & state-> guest_gdt;   state-> guest_tss.esp0=(panjang) (& halaman-> regs + 1);  state-> guest_tss.ss0=LGUEST_DS;   state-> guest_tss.io_bitmap_base=sizeof (state-> guest_tss);   setup_default_gdt_entries (negara bagian);  setup_default_idt_entries (status, default_idt_entries);   get_cpu_gdt_table (i) [GDT_ENTRY_LGUEST_CS]=FULL_EXEC_SEGMENT; get_cpu_gdt_table (i) [GDT_ENTRY_LGUEST_DS]=FULL_SEGMENT; }   lguest_entry.offset=(panjang) switch_to_guest + switcher_offset (); lguest_entry.segment=LGUEST_CS;     lock_cpu_hotplug (); jika (cpu_has_pge) {  cpu_had_pge=1;  on_each_cpu (adjust_pge, (void  0, 0, 1);  clear_bit (X86_FEATURE_PGE, boot_cpu_data.x86_capability); } unlock_cpu_hotplug (); };    [ drivers/lguest/core.c ]   int run_guest (struct lguest lg, unsigned long __user user) {  while (! lg-> dead) {  jika (lg-> hcall) do_hypercalls (lg);   if (lg-> pending_notify) { if (put_user (lg-> pending_notify, user)) kembali -EFAULT; return sizeof (lg-> pending_notify); }   if (signal_pending (current)) kembali -ERESTARTSYS;   if (lg-> break_out) kembali -EAGAIN;   maybe_do_interrupt (lg);   try_to_freeze ();   jika (lg-> mati) istirahat;   jika (lg-> dihentikan) { set_current_state (TASK_INTERRUPTIBLE); susunan acara(); terus; }   local_irq_disable ();   lguest_arch_run_guest (lg);   local_irq_enable ();   lguest_arch_handle_trap (lg); }   kembali -ENOENT; }   int lguest_address_ok (const struct lguest lg, unsigned long addr, unsigned long len) { kembali (addr + len) / PAGE_SIZE  pfn_limit && (addr + len>=addr); }   void __lgread (struct lguest lg, void b, unsigned long addr, unsigned bytes) { if (! lguest_address_ok (lg, addr, bytes) || copy_from_user (b, lg-> mem_base + addr, bytes)!=0) {  memset (b, 0, byte); kill_guest (lg, "alamat baca buruk% # lx len% u", addr, byte); } }   void __lgwrite (struct lguest lg, unsigned long addr, const void b, byte tidak bertanda tangan) { if (! lguest_address_ok (lg, addr, bytes) || copy_to_user (lg-> mem_base + addr, b, bytes)!=0) kill_guest (lg, "alamat tulis salah% # lx len% u", addr, bytes); }    [ drivers/lguest/lg.h ]   #define lgread (lg, addr, type)  ({type _v; __lgread ((lg), & _v, (addr), sizeof (_v)); _v;})   #tentukan lgwrite (lg, addr, type, val)  lakukan { typecheck (tipe, val);  __lgwrite ((lg), (addr), & (val), sizeof (val));  } sementara (0)    [ drivers/lguest/x86/core.c ]   void lguest_arch_run_guest (struct lguest lg) {  jika (lg-> ts) lguest_set_ts ();   jika (boot_cpu_has (X86_FEATURE_SEP)) wrmsr (MSR_IA32_SYSENTER_CS, 0, 0);   run_guest_once (lg, lguest_pages (raw_smp_processor_id ()));     if (lg-> regs-> trapnum==14) lg-> arch.last_pagefault=read_cr2 ();  else if (lg-> regs-> trapnum==7) math_state_restore ();   jika (boot_cpu_has (X86_FEATURE_SEP)) wrmsr (MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); }   void lguest_arch_handle_trap (struct lguest lg) { saklar (lg-> regs-> trapnum) { kasus 13:  if (lg-> regs-> errcode==0) { jika (emulate_insn (lg)) kembali; } istirahat; kasus 14:  if (demand_page (lg, lg-> arch.last_pagefault, lg-> regs-> errcode)) kembali;   if (lg-> lguest_data && put_user (lg-> arch.last_pagefault, & lg-> lguest_data-> cr2)) kill_guest (lg, "Menulis cr2"); istirahat; kasus 7:  if (! lg-> ts) kembali; istirahat; kasus 32 ... 255:  cond_resched (); kembali; kasus LGUEST_TRAP_ENTRY:  lg-> hcall=(struct hcall_args  lg-> regs; kembali; }   if (! deliver_trap (lg, lg-> regs-> trapnum))  kill_guest (lg, "perangkap tidak tertangani% li di% # lx (% # lx)", lg-> regs-> trapnum, lg-> regs-> eip, lg-> regs-> trapnum==14? lg-> arch.last_pagefault : lg-> regs-> errcode); }     [ drivers/lguest/hypercalls.c ]   void do_hypercalls (struct lguest lg) {  if (tidak mungkin (! lg-> lguest_data)) {  menginisialisasi (lg);  lg-> hcall=NULL; kembali; }   do_async_hcalls (lg);   if (! lg-> pending_notify) { do_hcall (lg, lg-> hcall);  lg-> hcall=NULL; } }   batal write_timestamp (struct lguest lg) { struct timespec sekarang; ktime_get_real_ts (& sekarang); if (copy_to_user (& lg-> lguest_data-> waktu, & sekarang, sizeof (struct timespec))) kill_guest (lg, "Stempel waktu penulisan"); }   static void do_hcall (struct lguest lg, struct hcall_args args) { saklar (args-> arg0) { kasus LHCALL_FLUSH_ASYNC:  istirahat; kasus LHCALL_LGUEST_INIT:  kill_guest (lg, "sudah memiliki lguest_data"); istirahat; kasus LHCALL_CRASH: {  char msg [LHCALL_RING_SIZE];  __lgread (lg, msg, args-> arg1, sizeof (msg)); msg [n]=' 0'; kill_guest (lg, "CRASH:% s", msg); istirahat; } kasus LHCALL_FLUSH_TLB:  if (args-> arg1) guest_pagetable_clear_all (lg); lain guest_pagetable_flush_user (lg); istirahat;   kasus LHCALL_NEW_PGTABLE: guest_new_pagetable (lg, args-> arg1); istirahat; kasus LHCALL_SET_STACK: guest_set_stack (lg, args-> arg1, args-> arg2, args-> arg3); istirahat; kasus LHCALL_SET_PTE: guest_set_pte (lg, args-> arg1, args-> arg2, __pte (args-> arg3)); istirahat; kasus LHCALL_SET_PMD: guest_set_pmd (lg, args-> arg1, args-> arg2); istirahat; kasus LHCALL_SET_CLOCKEVENT: guest_set_clockevent (lg, args-> arg1); istirahat; kasus LHCALL_TS:  lg-> ts=args-> arg1; istirahat; kasus LHCALL_HALT:  lg-> dihentikan=1; istirahat; kasus LHCALL_NOTIFY: lg-> pending_notify=args-> arg1; istirahat; default:  if (lguest_arch_do_hcall (lg, args)) kill_guest (lg, "Hypercall buruk% li  n", args-> arg0); } }    [ drivers/lguest/x86/core.c ]   int lguest_arch_do_hcall (struct lguest lg, struct hcall_args args) { saklar (args-> arg0) { kasus LHCALL_LOAD_GDT: load_guest_gdt (lg, args-> arg1, args-> arg2); istirahat; case LHCALL_LOAD_IDT_ENTRY: load_guest_idt_entry (lg, args-> arg1, args-> arg2, args-> arg3); istirahat; kasus LHCALL_LOAD_TLS: guest_load_tls (lg, args-> arg1); istirahat; default:  kembali -EIO; } kembali 0; }   [ drivers/lguest/hypercalls.c ]   statis void do_async_hcalls (struct lguest lg) { unsigned int i; u8 st [FIRST_EXTERNAL_VECTOR+irq];   if (copy_from_user (& st, & lg-> lguest_data-> hcall_status, sizeof (st))) kembali;   untuk (i=0; i  panggilan_berikutnya;   jika (st [n]==0xFF) istirahat;   jika (++ lg-> next_hcall==LHCALL_RING_SIZE) lg-> next_hcall=0;   jika (copy_from_user (& args, & lg-> lguest_data-> hcalls [i/ptes_per_page] , sizeof (struct hcall_args))) { kill_guest (lg, "Mengambil hypercalls asinkron"); istirahat; }   do_hcall (lg, & args);   jika (put_user (0xFF, & lg-> lguest_data-> hcall_status [i/ptes_per_page] )) { kill_guest (lg, "Menulis hasil untuk hypercall async"); istirahat; }   if (lg-> pending_notify) istirahat; } }   void statis menginisialisasi (struct lguest lg) {  if (lg-> hcall-> arg0!=LHCALL_LGUEST_INIT) { kill_guest (lg, "hypercall% li sebelum INIT", lg-> hcall-> arg0); kembali; }  jika (lguest_arch_init_hypercalls (lg)) kill_guest (lg, "halaman tamu buruk% p", lg-> lguest_data);   if (get_user (lg-> noirq_start, & lg-> lguest_data-> noirq_start) || get_user (lg-> noirq_end, & lg-> lguest_data-> noirq_end)) kill_guest (lg, "halaman tamu buruk% p", lg-> lguest_data);   write_timestamp (lg);   halaman_tabel_guest_data_init (lg);   guest_pagetable_clear_all (lg); }   [ drivers/lguest/x86/core.c ]   int lguest_arch_init_hypercalls (struct lguest lg) { u32 tsc_speed;   if (! lguest_address_ok (lg, lg-> hcall-> arg1, sizeof  lg-> lguest_data))) kembali -EFAULT;   lg-> lguest_data=lg-> mem_base + lg-> hcall-> arg1;   jika (boot_cpu_has (X86_FEATURE_CONSTANT_TSC) &&! check_tsc_unstable ()) tsc_speed=tsc_khz; lain tsc_speed=0; if (put_user (tsc_speed, & lg-> lguest_data-> tsc_khz)) kembali -EFAULT;   if (! check_syscall_vector (lg)) kill_guest (lg, "vektor syscall buruk");  kembali 0; }   void lguest_arch_setup_regs (struct lguest lg, unsigned long start) { struct lguest_regs regs=lg-> regs;   regs-> ds=regs-> es=regs-> ss=__KERNEL_DS | GUEST_PL; regs-> cs=__KERNEL_CS | GUEST_PL;   regs-> eflags=X86_EFLAGS_IF | 0x2;   regs-> eip=mulai;     setup_guest_gdt (lg); }   static int emulate_insn (struct lguest lg) { u8 insn; unsigned int insnlen=0, in=0, shift=0;  physaddr panjang unsigned=guest_pa (lg, lg-> regs-> eip);   if ((lg-> regs-> cs & 3)!=GUEST_PL) kembali 0;   insn=lgread (lg, physaddr, u8);   jika (insn==0x66) { shift=16;  insnlen=1; insn=lgread (lg, physaddr + insnlen, u8); }   sakelar (dalam & 0xFE) { kasus 0xE4: insnlen +=2; dalam=1; istirahat; kasus 0xEC: insnlen +=1; dalam=1; istirahat; kasus 0xE6: insnlen +=2; istirahat; kasus 0xEE: insnlen +=1; istirahat; default:  kembali 0; }   jika (dalam) {  jika (dalam & 0x1) lg-> regs-> eax=0xFFFFFFFF; lain lg-> regs-> eax |=(0xFFFF  regs-> eip +=insnlen;  kembali 1; }   [ drivers/lguest/interrupts_and_traps.c ]   void guest_set_clockevent (struct lguest lg, delta panjang unsigned) { ktime_t kedaluwarsa;  if (tidak mungkin (delta==0)) {  hrtimer_cancel (& lg-> hrt); kembali; }   kedaluwarsa=ktime_add_ns (ktime_get_real (), delta); hrtimer_start (& lg-> hrt, expires, HRTIMER_MODE_ABS); }   enum statis hrtimer_restart clockdev_fn (struct hrtimer timer) { struct lguest lg=container_of (timer, struct lguest, hrt);   set_bit (0, lg-> irqs_pending);  jika (lg-> dihentikan) wake_up_process (lg-> tsk); kembali HRTIMER_NORESTART; }   void init_clockdev (struct lguest lg) { hrtimer_init (& lg-> hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); lg-> hrt.function=clockdev_fn; }   void maybe_do_interrupt (struct lguest lg) { unsigned int irq; DECLARE_BITMAP (blk, LGUEST_IRQS); struct desc_struct idt;   if (! lg-> lguest_data) kembali;   jika (copy_from_user (& blk, lg-> lguest_data-> diblokir_interupsi, sizeof (blk))) kembali;  bitmap_andnot (blk, lg-> irqs_pending, blk, LGUEST_IRQS);   irq=find_first_bit (blk, LGUEST_IRQS);  if (irq>=LGUEST_IRQS) kembali;   if (lg-> regs-> eip>=lg-> noirq_start && lg-> regs-> eip  noirq_end) kembali;   jika (lg-> dihentikan) {  jika (put_user (X86_EFLAGS_IF, & lg-> lguest_data-> irq_enabled)) kill_guest (lg, "Mengaktifkan kembali interupsi"); lg-> dihentikan=0; } lain {  u32 irq_enabled; if (get_user (irq_enabled, & lg-> lguest_data-> irq_enabled)) irq_enabled=0; if (! irq_enabled) kembali; }   idt=& lg-> arch.idt [FIRST_EXTERNAL_VECTOR+irq];  if (idt_present (idt-> a, idt-> b)) {  clear_bit (irq, lg-> irqs_pending);  set_guest_interrupt (lg, idt-> a, idt-> b, 0); }   write_timestamp (lg); }    static void set_guest_interrupt (struct lguest lg, u32 lo, u32 hi, int has_err) { gstack panjang tanpa tanda tangan, origstack; u32 eflags, ss, irq_enable; virtstack panjang tanpa tanda tangan;   if ((lg-> regs-> ss & 0x3)!=GUEST_PL) {  virtstack=lg-> esp1; ss=lg-> ss1;  origstack=gstack=guest_pa (lg, virtstack);  push_guest_stack (lg, & gstack, lg-> regs-> ss); push_guest_stack (lg, & gstack, lg-> regs-> esp); } lain {  virtstack=lg-> regs-> esp; ss=lg-> regs-> ss;  origstack=gstack=guest_pa (lg, virtstack); }   eflags=lg-> regs-> eflags; if (get_user (irq_enable, & lg-> lguest_data-> irq_enabled)==0 &&! (irq_enable & X86_EFLAGS_IF)) eflags &=~ X86_EFLAGS_IF;   push_guest_stack (lg, & gstack, eflags); push_guest_stack (lg, & gstack, lg-> regs-> cs); push_guest_stack (lg, & gstack, lg-> regs-> eip);   jika (has_err) push_guest_stack (lg, & gstack, lg-> regs-> errcode);   lg-> regs-> ss=ss; lg-> regs-> esp=virtstack + (gstack - origstack); lg-> regs-> cs=(__KERNEL_CS | GUEST_PL); lg-> regs-> eip=idt_address (lo, hi);   if (idt_type (lo, hi)==0xE) if (put_user (0, & lg-> lguest_data-> irq_enabled)) kill_guest (lg, "Menonaktifkan interupsi"); }   static int has_err (perangkap int unsigned) { kembali (trap==8 || (trap>=10 && trap [optind+1] =ARRAY_SIZE (lg-> arch. idt)) kembali 0;   if (! idt_present (lg-> arch.idt [6] . a, lg-> arch.idt [num]. b)) kembali 0; set_guest_interrupt (lg, lg-> arch.idt [num]. a, lg-> arch.idt [num]. b, has_err (num)); kembali 1; }   void load_guest_idt_entry (struct lguest lg, unsigned int num, u32 lo, u32 hi) {  if (num==2 || num==8 || num==15 || num==LGUEST_TRAP_ENTRY) kembali;   lg-> diubah |=CHANGED_IDT;   if (num>=ARRAY_SIZE (lg-> arch.idt)) kill_guest (lg, "Menyetel entri idt% u", num); lain set_trap (lg, & lg-> arch.idt [num], num, lo, hai); }   kekosongan statis default_idt_entry (struct desc_struct idt, perangkap int, const unsigned penangan panjang) {  bendera u32=0x8e00;   jika (perangkap==LGUEST_TRAP_ENTRY) bendera |=(GUEST_PL  a=(LGUEST_CS  b=(handler & 0xFFFF0000) | bendera; }   void setup_default_idt_entries (status struct lguest_ro_state *, const unsigned long def) { unsigned int i;  untuk (i=0; i  guest_idt); i ++) default_idt_entry (& state-> guest_idt [i], i, def [i]); }   static void set_trap (struct lguest lg, struct desc_struct trap, unsigned int num, u32 lo, u32 hi) { u8 type=idt_type (lo, hai);   if (! idt_present (lo, hi)) { perangkap-> a=perangkap-> b=0; kembali; }   if (ketik!=0xE && ketik!=0xF) kill_guest (lg, "jenis IDT buruk% i", jenis);   trap-> a=((__KERNEL_CS | GUEST_PL)  b=(hi & 0xFFFFEF00); }   kosongkan copy_traps (const struct lguest lg, struct desc_struct idt, const unsigned long def) { unsigned int i;   untuk (i=0; i  arch.idt); i ++) {  if (! direct_trap (i)) terus;   if (idt_type (lg-> arch.idt [i]. a, lg-> arch.idt [i] .b)==0xF) idt [i]=lg-> arch.idt [i]; lain  default_idt_entry (& idt [i], i, def [i]); } }   static int direct_trap (unsigned int num) {  jika (num>=FIRST_EXTERNAL_VECTOR &&! could_be_syscall (num)) kembali 0;   return num!=14 && num!=13 && num!=7 && num!=LGUEST_TRAP_ENTRY; }    void pin_stack_pages (struct lguest lg) { unsigned int i;   untuk (i=0; i  stack_pages; i ++)  pin_page (lg, lg-> esp1 - 1 - i PAGE_SIZE); }   void guest_set_stack (struct lguest lg, u32 seg, u32 esp, halaman int unsigned) {  jika ((seg & 0x3)!=GUEST_PL) kill_guest (lg, "segmen tumpukan buruk% i", seg);  if (halaman> 2) kill_guest (lg, "halaman tumpukan buruk% u", halaman);  lg-> ss1=seg; lg-> esp1=esp; lg-> stack_pages=halaman;  pin_stack_pages (lg); }     [ drivers/lguest/page_tables.c ]     static pgd_t spgd_addr (struct lguest lg, u32 i, unsigned long vaddr) { unsigned int index=pgd_index (vaddr);   jika (indeks>=SWITCHER_PGD_INDEX) { kill_guest (lg, "mencoba mengakses halaman switcher"); indeks=0; }  kembali & lg-> pgdirs [i]. pgdir [index]; }   static pte_t spte_addr (struct lguest lg, pgd_t spgd, unsigned long vaddr) { pte_t halaman=__va (pgd_pfn (spgd) > (PGDIR_SHIFT); kembali lg-> pgdirs [lg->pgdidx]. gpgdir + index sizeof (pgd_t); }  statis gpte_addr panjang unsigned (struct lguest lg, pgd_t gpgd, vaddr panjang unsigned) { gpage panjang yang tidak bertanda tangan=pgd_pfn (gpgd) > HALAMAN_SHIFT)% PTRS_PER_PTE) sizeof (pte_t); }   int demand_page (struct lguest lg, unsigned long vaddr, int errcode) { pgd_t gpgd; pgd_t spgd; gpte_ptr panjang tak bertanda tangan; pte_t gpte; pte_t spte;   gpgd=lgread (lg, gpgd_addr (lg, vaddr), pgd_t);  if (! (pgd_flags (gpgd) & _PAGE_PRESENT)) kembali 0;   spgd=spgd_addr (lg, lg-> pgdidx, vaddr); if (! (pgd_flags  spgd) & _PAGE_PRESENT)) {  ptepage panjang unsigned=get_zeroed_page (GFP_KERNEL);  if (! ptepage) { kill_guest (lg, "kehabisan memori mengalokasikan halaman pte"); kembali 0; }  check_gpgd (lg, gpgd);  spgd=__pgd (__ pa (ptepage) | pgd_flags (gpgd)); }   gpte_ptr=gpte_addr (lg, gpgd, vaddr); gpte=lgread (lg, gpte_ptr, pte_t);   if (! (pte_flags (gpte) & _PAGE_PRESENT)) kembali 0;   if ((errcode & 2) &&! (pte_flags (gpte) & _PAGE_RW)) kembali 0;   if ((errcode & 4) &&! (pte_flags (gpte) & _PAGE_USER)) kembali 0;   check_gpte (lg, gpte);   gpte=pte_mkyoung (gpte); jika (errcode & 2) gpte=pte_mkdirty (gpte);   spte=spte_addr (lg, spgd, vaddr);  release_pte  spte);   jika (pte_dirty (gpte)) spte=gpte_to_spte (lg, gpte, 1); lain  spte=gpte_to_spte (lg, pte_wrprotect (gpte), 0);   lgwrite (lg, gpte_ptr, pte_t, gpte);   kembali 1; }   statis pte_t gpte_to_spte (struct lguest lg, pte_t gpte, int tulis) { pfn panjang unsigned, base, flags;   flags=(pte_flags (gpte) & ~ _PAGE_GLOBAL);   base=(panjang unsigned) lg-> mem_base / PAGE_SIZE;   pfn=get_pfn (basis + pte_pfn (gpte), tulis); jika (pfn==-1UL) { kill_guest (lg, "gagal mendapatkan halaman% lu", pte_pfn (gpte));  bendera=0; }  return pfn_pte (pfn, __pgprot (flags)); }   get_pfn panjang unsigned statis (virtpfn panjang unsigned, int write) { halaman struct *;  ret panjang unsigned=-1UL;   down_read (& current-> mm-> mmap_sem); if (get_user_pages (current, current-> mm, virtpfn  mmap_sem); ret kembali; }   static int page_writable (struct lguest lg, unsigned long vaddr) { pgd_t spgd; bendera panjang tak bertanda tangan;   spgd=spgd_addr (lg, lg-> pgdidx, vaddr); if (! (pgd_flags  spgd) & _PAGE_PRESENT)) kembali 0;   flags=pte_flags  (spte_addr (lg, spgd, vaddr)));  kembali (bendera & (_PAGE_PRESENT | _PAGE_RW))==(_PAGE_PRESENT | _PAGE_RW); }   void pin_page (struct lguest lg, unsigned long vaddr) { if (! page_writable (lg, vaddr) &&! demand_page (lg, vaddr, 2)) kill_guest (lg, "halaman tumpukan buruk% # lx", vaddr); }   void guest_set_pmd (struct lguest lg, unsigned long gpgdir, u32 idx) { int pgdir;   jika (idx>=SWITCHER_PGD_INDEX) kembali;   pgdir=find_pgdir (lg, gpgdir); jika (pgdir  pgdirs))  release_pgd (lg, lg-> pgdirs [pgdir]. pgdir + idx); }   void guest_set_pte (struct lguest lg, gpgdir panjang unsigned, long vaddr unsigned, pte_t gpte) {  if (vaddr>=lg-> kernel_address) { unsigned int i; untuk (i=0; i  pgdirs); i ++) if (lg-> pgdirs [i]. pgdir) do_set_pte (lg, i, vaddr, gpte); } lain {  int pgdir=find_pgdir (lg, gpgdir); if (pgdir!=ARRAY_SIZE (lg-> pgdirs))  do_set_pte (lg, pgdir, vaddr, gpte); } }   static void do_set_pte (struct lguest lg, int idx, vaddr panjang unsigned, pte_t gpte) {  pgd_t spgd=spgd_addr (lg, idx, vaddr);   jika (pgd_flags  spgd) & _PAGE_PRESENT) {  pte_t spte=spte_addr (lg, spgd, vaddr); release_pte  spte);   if (pte_flags (gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) { check_gpte (lg, gpte); spte=gpte_to_spte (lg, gpte, pte_flags (gpte) & _PAGE_DIRTY); } lain  spte=__pte (0); } }   void guest_new_pagetable (struct lguest lg, unsigned long pgtable) { int newpgdir, repin=0;   newpgdir=find_pgdir (lg, pgtable);  if (newpgdir==ARRAY_SIZE (lg-> pgdirs)) newpgdir=new_pgdir (lg, pgtable, & repin);  lg-> pgdidx=newpgdir;  jika (repin) pin_stack_pages (lg); }   statis unsigned int new_pgdir (struct lguest lg, gpgdir panjang tanpa tanda tangan, int blank_pgdir) { unsigned int next;   berikutnya=random32 ()% ARRAY_SIZE (lg-> pgdirs);  jika (! lg-> pgdirs [next]. pgdir) { lg-> pgdirs [next]. pgdir=(pgd_t  get_zeroed_page (GFP_KERNEL);  jika (! lg-> pgdirs [next]. pgdir) berikutnya=lg-> pgdidx; lain  blank_pgdir=1; }  lg-> pgdirs [next]. gpgdir=gpgdir;  flush_user_mappings (lg, selanjutnya);  kembali berikutnya; }   void guest_pagetable_flush_user (struct lguest lg) {  flush_user_mappings (lg, lg-> pgdidx); }    static void flush_user_mappings (struct lguest lg, int idx) { unsigned int i;  untuk (i=0; i  kernel_address); i ++) release_pgd (lg, lg-> pgdirs [idx]. pgdir + i); }   static void release_pgd (struct lguest lg, pgd_t spgd) {  jika (pgd_flags  spgd) & _PAGE_PRESENT) { unsigned int i;  pte_t ptepage=__va (pgd_pfn  spgd)  pgdirs); i ++) if (lg-> pgdirs [i]. pgdir)  untuk (j=0; j  pgdirs [i]. pgdir + j); }   void guest_pagetable_clear_all (struct lguest lg) { release_all_pagetables (lg);  pin_stack_pages (lg); }    void map_switcher_in_guest (struct lguest lg, struct lguest_pages halaman) { pte_t switcher_pte_page=__get_cpu_var (switcher_pte_pages); pgd_t switcher_pgd; pte_t regs_pte;   switcher_pgd=__pgd (__ pa (switcher_pte_page) | _PAGE_KERNEL);  lg-> pgdirs [lg->pgdidx]. pgdir [SWITCHER_PGD_INDEX]=switcher_pgd;   regs_pte=pfn_pte (__pa (lg-> regs_page)>> PAGE_SHIFT, __pgprot (_PAGE_KERNEL)); switcher_pte_page [(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE]=regs_pte; }    int init_guest_pagetable (struct lguest lg, unsigned long pgtable) {  lg-> pgdidx=0; lg-> pgdirs [lg->pgdidx]. gpgdir=pgtable; lg-> pgdirs [lg->pgdidx]. pgdir=(pgd_t  get_zeroed_page (GFP_KERNEL); jika (! lg-> pgdirs [lg->pgdidx]. pgdir) kembali -ENOMEM; kembali 0; }   batal page_table_guest_data_init (struct lguest lg) {  if (get_user (lg-> kernel_address, & lg-> lguest_data-> kernel_address)  || put_user (4U 1024 1024, & lg-> lguest_data-> reserve_mem) || put_user (lg-> pgdirs [next]. gpgdir, & lg-> lguest_data-> pgdir)) kill_guest (lg, "halaman tamu buruk% p", lg-> lguest_data);   if (pgd_index (lg-> kernel_address)>=SWITCHER_PGD_INDEX) kill_guest (lg, "alamat kernel buruk% # lx", lg-> kernel_address); }   void free_guest_pagetable (struct lguest lg) { unsigned int i;   release_all_pagetables (lg);  untuk (i=0; i  pgdirs); i ++) free_page ((long) lg-> pgdirs [i]. pgdir); }   __init int init_pagetables (halaman struct switcher_page, halaman int unsigned) { unsigned int i;  for_each_possible_cpu (i) { switcher_pte_page (i)=(pte_t  get_zeroed_page (GFP_KERNEL); if (! switcher_pte_page (i)) { free_switcher_pte_pages (); kembali -ENOMEM; } populate_switcher_pte_page (i, switcher_page, halaman); } kembali 0; }    static __init void populate_switcher_pte_page (unsigned int cpu, halaman struct switcher_page [], halaman int unsigned) { unsigned int i; pte_t pte=switcher_pte_page (cpu);   untuk (i=0; i  [ drivers/lguest/segments.c ]     static int ignored_gdt (unsigned int num) { kembali (num==GDT_ENTRY_TSS || num==GDT_ENTRY_LGUEST_CS || num==GDT_ENTRY_LGUEST_DS || num==GDT_ENTRY_DOUBLEFAULT_TSS); }   void setup_default_gdt_entries (struct lguest_ro_state state) { struct desc_struct gdt=state-> guest_gdt; unsigned long tss=(unsigned long) & state-> guest_tss;   gdt [GDT_ENTRY_LGUEST_CS]=FULL_EXEC_SEGMENT; gdt [GDT_ENTRY_LGUEST_DS]=FULL_SEGMENT;   gdt [GDT_ENTRY_TSS]. a=0x00000067 | (tss > 16) & 0x000000FF); }   batal setup_guest_gdt (struct lguest lg) {  lg-> arch.gdt [GDT_ENTRY_KERNEL_CS]=FULL_EXEC_SEGMENT; lg-> arch.gdt [GDT_ENTRY_KERNEL_DS]=FULL_SEGMENT;  lg-> arch.gdt [GDT_ENTRY_KERNEL_CS]. b |=(GUEST_PL  arch.gdt [GDT_ENTRY_KERNEL_DS]. b |=(GUEST_PL  ARRAY_SIZE (lg-> arch.gdt)) kill_guest (lg, "terlalu banyak entri gdt% i", num);   __lgread (lg, lg-> arch.gdt, tabel, num sizeof (lg-> arch.gdt [0])); fixup_gdt_table (lg, 0, ARRAY_SIZE (lg-> arch.gdt));  lg-> diubah |=CHANGED_GDT; }   void guest_load_tls (struct lguest lg, gtls panjang tidak bertanda tangan) { struct desc_struct tls=& lg-> arch.gdt [GDT_ENTRY_TLS_MIN];  __lgread (lg, tls, gtls, sizeof  tls) GDT_ENTRY_TLS_ENTRIES); fixup_gdt_table (lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX + 1);  lg-> diubah |=CHANGED_GDT_TLS; }    static void fixup_gdt_table (struct lguest lg, unsigned start, unsigned end) { unsigned int i;  untuk (i=start; i lengkungan. gdt [i]. b & 0x00006000)==0) lg-> arch.gdt [i]. b |=(GUEST_PL  arch.gdt [i]. b |=0x00000100; } }   kosongkan copy_gdt (const struct lguest lg, struct desc_struct gdt) { unsigned int i;   untuk (i=0; i  arch.gdt [i]; }   batal copy_gdt_tls (const struct lguest lg, struct desc_struct gdt) { unsigned int i;  untuk (i=GDT_ENTRY_TLS_MIN; i  arch.gdt [i]; }     $ make Switcher   [ drivers/lguest/x86/core.c ]   static void copy_in_guest_info (halaman struct lguest lg, struct lguest_pages  {  if (__get_cpu_var (last_guest)!=lg || lg-> last_pages!=pages) { __get_cpu_var (last_guest)=lg; lg-> last_pages=halaman; lg-> diubah=CHANGED_ALL; }    halaman-> status.host_cr3=__pa (saat ini-> mm-> pgd);  map_switcher_in_guest (lg, halaman);  halaman-> state.guest_tss.esp1=lg-> esp1; halaman-> state.guest_tss.ss1=lg-> ss1;   jika (lg-> diubah & CHANGED_IDT) copy_traps (lg, halaman-> state.guest_idt, default_idt_entries);   jika (lg-> diubah & CHANGED_GDT) copy_gdt (lg, halaman-> state.guest_gdt);  lain jika (lg-> diubah & CHANGED_GDT_TLS) copy_gdt_tls (lg, halaman-> state.guest_gdt);   lg-> berubah=0; }   statis void run_guest_once (struct lguest lg, struct lguest_pages halaman) {  clobber int unsigned;   copy_in_guest_info (lg, halaman);   lg-> regs-> trapnum=256;   asm volatile ("pushf; lcall lguest_entry"  : "=a" (pemanjat), "=b" (pemanjat)  : "0" (halaman), "1" (__ pa (lg-> pgdirs [ drivers/lguest/x86/core.c ] . pgdir))  : "memory", "% edx", "% ecx", "% edi", "% esi"); }    [ drivers/lguest/x86/switcher_32.S ]          #include  #include  #include  #include 

#include

.teks ENTRY (start_switcher_text) ENTRY (switch_to_guest) pushl% es pushl% ds pushl% gs pushl% fs pushl% ebp movl% esp, LGUEST_PAGES_host_sp (% eax) movl% eax,% edx addl $ LGUEST_PAGES_regs,% edx movl% edx,% esp lgdt LGUEST_PAGES_guest_gdt_desc (% eax) lidt LGUEST_PAGES_guest_idt_desc (% eax) movl $ (GDT_ENTRY_TSS 8),% edx ltr% dx movl (LGUEST_PAGES_host_gdt_desc + 2) (% eax),% edx danb $ 0xFD, (GDT_ENTRY_TSS 8 + 5) (% edx) movl% ebx,% cr3 popl% eax popl% ebx popl% ecx popl% edx popl% esi popl% edi popl% ebp popl% gs popl% fs popl% ds popl% es addl $ 8,% esp iret #tentukan SWITCH_TO_HOST pushl% es; pushl% ds; pushl% fs; pushl% gs; pushl% ebp; pushl% edi; pushl% esi; pushl% edx; pushl% ecx; pushl% ebx; pushl% eax; movl $ (LGUEST_DS),% eax; movl% eax,% ds; movl% esp,% eax; dan l $ (~ (1 8) && ( N [i/ptes_per_page] 14) && ( N 17) dorong $ 0 .berakhir jika dorong $ N jmp TARGET MELURUSKAN .endm .macro IRQ_STUBS TARGET TERAKHIR PERTAMA irq= PERTAMA .rept LAST- FIRST + 1 IRQ_STUB irq TARGET irq=irq + 1 .endr .endm .data .global default_idt_entries default_idt_entries: .teks IRQ_STUBS 0 1 return_to_host IRQ_STUB 2 handle_nmi IRQ_STUBS 3 31 return_to_host IRQ_STUBS 32127 deliver_to_host IRQ_STUB 128 return_to_host IRQ_STUBS 129255 deliver_to_host handle_nmi: addl $ 8,% esp iret ENTRY (end_switcher_text) $ membuat Penguasaan [ drivers/lguest/x86/core.c ] [ arch/x86/lguest/boot.c ] [ arch/x86/lguest/i386_head.S ] [ drivers/lguest/interrupts_and_traps.c ] [ drivers/lguest/page_tables.c ] [ Documentation/lguest/lguest.c ] [ drivers/lguest/x86/switcher_32.S ] [ Documentation/lguest/lguest.c ] Read More

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments