设为首页 收藏本站
查看: 42165|回复: 0

[经验分享] kernel 3.10代码分析--KVM相关--虚拟机运行

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-12-24 15:09:11 | 显示全部楼层 |阅读模式
  1、基本原理
KVM虚拟机通过字符设备/dev/kvm的ioctl接口创建和运行,相关原理见之前的文章说明。
虚拟机的运行通过/dev/kvm设备ioctl VCPU接口的KVM_RUN指令实现,VMVCPU创建好并完成初始化后,就可以调度该虚拟机运行了,通常,一个VCPU对应于一个线程,虚拟机运行的本质为调度该虚拟机相关的VCPU所在线程运行。虚拟机(VCPU)的运行主要任务是要进行上下文切换,上下文主要包括相关寄存器、APIC状态、TLB等,通常上下文切换的过程如下:
1、    保存当前的上下文。
2、    使用kvm_vcpu结构体中的上下文信息,加载到物理CPU中。
3、    执行kvm_x86_ops中的run_vcpu函数,调用硬件相关的指令(VMLAUNCH),进入虚拟机运行环境中
虚拟机运行于qemu-kvm的进程上下文中,从硬件的角度看,虚拟机的运行过程,实质为相关指令的执行过程,虚拟机编译后的也就是相应的CPU指令序列,而虚拟机的指令跟Host机的指令执行过程并没有太多的差别,最关键的差别为“敏感指令”(通常为IO、内存等关键操作)的执行,这也是虚拟化实现的本质所在,当在虚拟机中(Guest模式)执行“敏感指令”时,会触发(由硬件触发)VM-exit,使当前CPU从Guest模式(non-root模式)切换到root模式,当前CPU的控制权随之转交给VMM(Hypervisor,KVM中即Host),由VMM进行相应的处理,处理完成后再次通过应该硬件指令(VMLAUNCH),重新进入到Guest模式,从而进入虚拟机运行环境中继续运行
本文简单解释及分析在3.10版本内核代码中的相关流程,用户态qemu-kvm部分暂不包括。

2、大致流程:
Qemu-kvm可以通过ioctl(KVM_RUN…)使虚拟机运行,最终进入内核态,由KVM相关内核流程处理,在内核态执行的大致过程如下:
kvm_vcpu_ioctl -->
    kvm_arch_vcpu_ioctl_run
具体由内核函数kvm_arch_vcpu_ioctl_run完成相关工作。主要流程如下:  
http://blog.iyunv.com/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAicAAAIaCAIAAAB01nr5AAAgAElEQVR4nOy9f4wcZZrnmeo+mhkWGmth3V4QKbM4SmZ78WQJMZLHsSuneuXukYzK0Za6xzpKbYg56zp9rHxXoeoBsT1WtcKD+FE9QAgpGS+YDmPWIyuttPugoH3EULTx0YTWtyx3eyENy4qTk7mTRyzOtUa2ehX3x1f1zMsbGVlZVZkVmW9+H31kRUbGjzcz4fnU875vRJRSRk5s3rz5008/LboVDAaDYVSUim7A8Aatw2AwGH0PWic3aB0Gg8Hoe9A6uUHrMBgMRt+D1skNWofBYDD6HrRObtA6DAaD0fegdXKD1mEwGIy+B62TG7QOg8Fg9D1ondygdRgMBqPvQet0iyiKgiCQl67rRlFUXHMYDAZj5GOsreO6ruM4tm3btu04jrochmGapr7vYyFN01ar5ThOmqYUD4PBYKw6xto6CN/34zjOLgdB4DiO53m+77fbbSl0WPEwGAzGqiPXOlcvf/nXb/3m/WdPnj3wrJH8H8cW8EnzrJMkiW3bcRzbtt1sNrEcRREqpKuXvyz8IxBiJHH9zGfnP/7tteuDTn+MQqKzdf7vM+df2Xmofv8Bg4kOH4vjOI5jz/PCMMwup2lq23aapqh4UPRAS67rLr75vxX+EQgxmJN7f/o3H32yrumQsS7RwToXX3mz8P/g1oHw0ScximNZlr0Usuw4TpIknuelS+6JlYii6Mqly4V/BELM5uj2g5eTz9Y7KTIGHLp1vvj086PbDxb+X9s6EB0+ho/sum7HHrYoitC35nleHMeO4/hLYds2rUPIOnBq38/Y1WZY6NZ5/9mThf93tj6IdVDKIFTrpGkahqFlWUmSxHHs+76sdxyH1iFkffg0ujjIHMhY79Ctc/bAs4X/R7Y+wDpRFGE+NCJrHUynDsOQ1iGkEOL6mQGnQca6hm6dMeleq99/IDp8LAgC27aTJJGPr1onDEOUQc1mM4oiy7KcpWAPGyHrxl8tdUswzAjdOoX/F7ZuRIePeZ7XbrfVjx9FkaxpNpuyPkkS7SYFtA4h6wOtY1iMtXXW8sXROuvA85MPF94GUji0jmFB66wyDLPO3Ld/qC4/P/mwugY8fu/38W9WBnhLY8+dD2TXP37v9/fc+YC6zb7yjo5N0rYkYwutY1iMr3WW5bZv3HLkvn2FN2N92HLzJpHKxhtvnfv2D3fcvnXXt7bJBjMTu7fcvKl+/4GNN946uWGzuu8jd1c33ngrdn9+8uHH7/0+2PWtbY/cXZWX2BgueWrbQ3vufGDPnQ/s+ta2LTdvwvLMxO4dt2/dcvMmsPHGWzfeeKu83HH71sK/JVIItI5hQevkMobWeX7yYfHHzMTujTfeKhvsuH0rihKYQK2EJjdslr323PmAqEJ1Bg4FqWy88dYdt2+FlrBQu+e7OPvct38olsLuMxO78TJbe5ExgdYxLGidXMbQOltu3vTI3VVZiaJHlp/a9hAWHrm7KpXH3Ld/CK+IdaRbTJWTlEeywfOTD6N4wpY4uLDj9q2P3F2t3fPdLTdv4ujOmEPrGBa0Ti7jZp3JDZu1Xqxd39qGTraZid2ijY033qoKA3roaB0pgOqKdXAiGG7H7VsnN2zecvOmfeUdohYcDW/V7z8A8aguJOMGrWNY0Dpf4eltD+3+x/eD3/36N76z8Z9h+Sdb9xTetoGC1K8WN/X7D8x9+4fSMyZ5X9ZIh1tdGRYS68iYDXaEQjBys+tb2yY3bEbXmagONQ18g7oHPW846Z47H9AGk8j4QOsYFrSOzl033Vb6atzwta8//dX+H/OANlBnqOtRr6gDPFh+attDMgugnrEOfCNHfuTuKpwxuWFz7Z7vSjG04/atUM7khs1itdo9391X3rGvvENdmTfPjYwDtI5hQevo/PieXZp1vrPxvsJbNWhEG9K1BVCXqGvEQJhEgLpEtc7khs3q5Le6UqlgXgCmq0kZtOP2reIhzJ0TmcFJ+8o7pLQiYwitY1jQOh1Qy51xKHTq9x/AWAuWt9y8SbSBTraZid2ypVhHHeyR3dVxHe34WJCrcJ7a9hBmIuwr71ANNDOxWz3IU9sekjqJ0wrGE1rHsKB1OjAzsXusCp0+krUOSh9xlVhnz50PYGI01mMZ7oGNUGNtuXmTjO6Q8YTWMSxonc5UNmwen0Knjzw/+bBWkaBXTSZGPz/5MExDl5AeoXUMC1qnM0/cu5eFDiHDAK1jWNA6uTzwD+9hoUNI4dA6hkXfrHN8/5PNFxrnootRnJjBW+9/VHgb+siZ+tmTMy8e3Xmo8CRCyIqgdQyLPljn5V3eO+c/jtOUDD/vX7p8fP+ThecRQnqH1jEs1mqdozsPXbj8ZeHJlKyIEweeKTyVENIjtI5hsVbrvH3mfOE5lKyUC5e/ZFcbGRVoHcNiTdY5uvNQ4QmUrI7Tz54sPJsQ0gu0jmGxJuucOPBM4dmzL0y5rrYgzAbBYrsty9q7i+12GMcasv0w8/aZ84VnE0J6gdYxLNZkneYLjcKzZ3fKllV1HI2KbVcdp5EkskY2U7fHESq2LTqp2PZcGKpqqfl+xbY1ar5f+AdflihOCs8mhPQCrWNYrMk6Z+pnC8+e3VGdIcyFYcW2ZZtGkuTVOvUomva82SCo+b5GPYpgnTCO1V3COKZ1COkjtI5hYb51ar4/7XlTrgtbVGwbL+GMuTCEJKY9b7HdnvY81SJVx0FZoylHutpwQK2QonUI6SO0jmFhuHXQUbbYbldse6HVWmi11ConTlNYpx5FkA0UUrasKdetR1HZsrBeq5YaSYLd61Eky6CRJCiDhhxah4wKtI5hYb51plw3O3IzF4Z4V9ZUbHs2COAkuAr7wjHayBBKpexQkIpmo2GD1iGjAq1jWJhvnbyFOE2nPa8eRTXfn282wzie9jzVOgutVnbYRmOh1VIPOELQOmRUoHUMC8Otk52cJguNJJn2vKrjYKgGk9PQ4SZzCmCdMI6zBQ02aCRJdlxnJDxE65BRgdYxLEy2DuqYOE3nm00RiVbrQDnwDcqasmXNN5uadbTRoC5eQc1U+GendYgx0DqGhcnWkcGVim3LCL9mHaglTlN0ss0GgToqo9Y66hw2TUKxMt1gynUxaDTk0DpkVKB1DAuTrSNSUTWgWge+mQtDyEZmUTeSBAtqraPOYcvWOuhbG5Vp07QOGSFoHcPCZOuQLtA6ZFSgdQyLNVnn5MyLhWdPsjrORRcLzyaE9AKtY1isyTrHHnys8OxJVseZ+tnCswkhvUDrGBZrfb7Orz/9vPAESlbBL/b9rPBsQkgv0DqGxVqtc3z/k4UnULJSWOiQEYLWMSzWap36/Qf+8rG/+ODK1cIzKemRt8+cf2n7wcJTCSE9QusYFn2wTv3+Ay/v8t4+c/695LPCU2ofOXHxYuFt6CMXLn/5zvmPX3/0ucKTCCErgtYxLPpjHSO57Ru3HLlvX+HNIGTMoXUMC1onF1qHkGGA1jEsaJ1caB1ChgFax7CgdXKhdQgZBmgdw4LWyYXWIWQYoHUMC1onF1qHkGGA1jEsaJ1caB1ChgFax7CgdXKhdQgZBmgdw4LWyYXWIWQYoHUMC1onF1qHkGGA1jEsaJ1caB1ChgFax7CgdXKhdQgZBmgdw4LW0Xl620MTt9wxccsdN3zt6//kH2ycuOWOf2X9YeGtImRsoXUMC1qnA5UNm0tL8c0bbgom3cKbRMjYQusYFrROB564d69Y5wd3bS+8PYSMM7SOYUHrdAblDgsdQgqH1jEsaJ3OoNxhoUNI4dA6hgWtk8u/+Ef/lIUOIYVD6xgW/bHOS9sPnn725K/e+s37ly4X/qhmkuWDK1ffOf/xmfrZV/f+tPAkQsiKoHUMiz5Y58SBZ3796eeFJ1bSCx9eu958oVF4HiGkd2gdw2Kt1jn24GMfXrteeDIlK6Jx5HjhqYSQHqF1DIu1WieKk8ElxzCOc/NmkvSy2SCo+X7HZmgsttv1KMquX2i1sFCPoo4brAMfXrt+7MHHCs8mhPQCrWNYrMk6R3ce0tJZxbbhgDCOy5YliB4qtl11nIptY6FsWVXHAdhmLgzFIrJjI0mmPU89UdVx5sJQTirZvx5Fs0GgblmPovlmU5anPQ+nRsafDYKa7wPxgeoVbLPYbstLaRWasdBqSeNV5sJQOw6Y9rwp18VZOm5Q83053WwQzDebs0Gg+Wk2CBpJUo8idWOxWnZlltPPniw8mxDSC7SOYbEm65yceVHLZfPNZsW2tZwrSTmM42nPw7+wCywVxrGauEVdkt8rtg3HTLkuFCXeqti2qq56FKlWwL5I2XNhWLas2SAI41hUhIPUfH/a88qWhS2zR0B78Ik06+DIEIkq2iyy15TrQhgdrVO2LJxuLgzxZU57nvr9LLRaOFrN98uWpR1kynVLpdKy9d+56GLh2YSQXqB1DIs1Waf5QiObzvBXthQTyNrzzWYjSRZaLcgmjOP5ZhMGggPUAkUkhNyqljVdUCskOXUjSXAQ2Cibiyu2LVl72vOyXlGtI1ZDs1HPybLWGPhMW6+WVtCkvJRm4Jg4Eb5M0YwcBN9PzfenXDfbWmlwF6I4KTybENILtI5hsSbrnKmfVRMZKg/0huFv/3ipAKr5/mwQoAACqC3UnAtVqGu0DZCC1coGyRf/SqpVzz7teeia05rU0TpTrtvdOuigQ8GUbaF0akEY+DhVx5H+PVhQLIUCThWYWGc2CDRzSLUXK9WbqEvewhdL6xCToHUMi35aRxJ0PYrwl770hkkpMxsEU64LB1QdB1aoOo4MzKia0QwkBYfqOZGEpFq1MihbFo6s2kVrsHT6lS0LQzt51pFjqsvqiEs9ikQD4gZ80my5huPIYJLa5my/2VwY4sOqn67m+zgLOuLQ1IVWi9YhJkHrGBYDsU68NHQhNYT2x7hmlGxPVEc9yGCP6rOsdaQaUNMx+rI6HrZsWXBSVgBZ66g9WnCMWkKp/YphHKtzHLTZELBII0myg1iodTSfyQZSvYl15PPK8BKtQ0yC1jEsBmUd/MUdL41wyAboapNuJTDlumpaVzvQBKl1ZAKCNvyjplqMfEy5rtRYMjKfbXDWRtoIkHpqlETSVIhNdIWBq5rv40OJkNRiTvWi+v2o1sG4l9YMiFOqN9U6cJgck9YhJkHrGBb9tw760NRUKEm5F+vkIZkUngB5tU681E+lHWHKdZGyMe04zzoYGkGzMcSC9RihkekJcN58symdfjXfF+vgG5CGaepVKyQMCMkGIhtUPNpwkXYcdS9pBq1DTILWMSz6bx1cwtJIkinXxXwqdUijew/bYrutCUkde88b1+mYatVSQ0vTyN0y6KJd36OKRz6O+hZMoF4kJOeCA2q+LzMIFtttmV2N7VWNqdflyGdRCyNtEkTVcdTWiuC1k4pcaR1iALSOYdFn68hoioxwLLRaGAuZDQJMHMBsAhWsxDS2HmcTQGkygVjGeNYBSEubHYBEDz81kkTtG1SHZyAzeYluNBxwWU+sFE3h2nWjtA4ZFWgdw6LP1gFacdAXJCn3PTuvlGwGH040hWtzE2gdMirQOobFQKxDhh9ah4wKtI5hQeuMKbQOGRVoHcOib9ZRL08RGkkiK2WAoXsXGeaAYdQkO7lA7drK3oRGBWdR13Q8nbZe7cfT2omX0qSOu8tm0gb1ZgSy47KfZbHdVs+unjQ7zyL7RWlrOnZ40jpkVKB1DIu+WSc7UzleGnhXl+Vmndk8iKvuMa0Ac6kx3ati26VSCQvqPQ60+63JwbGAI8iOecP1eReE4qTqWIjcdgHtR1ovlUrqZ5EZ0nLjHJnIJw3DXIPszeLUy0jVKdHx0pxpnFTufCrHjJduAyqT7rQ1spLWIaMIrWNY9NM62n1fcGFm9jKUOHMZpqTajrdKy7ohXrrOJptM1fnT6s3N8uhiHbXxceaCITm+Op9NrKOdOnu9jvoSk/rU7bUN4k7XFUHSUGl2++wptA1oHTIq0DqGRT+to13/X7FtefCBZpqOlzGisunYHaS5QW51I3dOG4R1YEHJ9XnWwb/oLluddeQqV/W+QctaR712Z1nrxJlbxtE6ZFSgdQyLfloHuRWpDZfuq9lWu+S+owPwJ/+052lTk7Xt5dLO7DWemnWkh61jn96y1llst9X7h3a0TqxUaauwjtzWUxZ6sY56VWn81f40eWRc9yPQOmRUoHUMiz5bR25AiasjNeuA7E3JVOSqUrWI0dxQtqz5ZlMGfrpYJ+/5Nz1aJ1aeU9fFOvFSYbcK6+DuajJihE/d3RkYB9LuM1RZuj1dXp+bOipG65ARgtYxLPpsHVGCJN+OPWzLot3PRs3geCSoOqKeHfNXrdP9ROrNNDuqJV567k5368AE0vXXo3UwNqN+Fhy5u3VgOPXdZXvYcCJVVLQOGRVoHcOi/9ZBbw+GKFZkHTX7Y4C9o3UqX70bjXanspVaR31UgVa7SJZHylbvPJ21Tqzcuq1362iNl8dvd7FOxzkU3a0DF2rDQrQOGRVoHcOi/9ZRHzsWLj2MoBfrYLyn4zCMVlJorlLXqI/qQeoXOj5fB09kkFJDagjteTxoWxjHcKp03GU76OThC+oEcfV7kFbhUNmH6OBONlrL5aTqepmtrm2vthNfqVYb0TpkhKB1DIs1Waf5QqN7JbEKirrN2iDuHTfM0DpkVKB1DIs1Wef1R59bddbTbsycd6VOf9GeFFd46i+QX731m8KzCSG9QOsYFmuyztGdhwrPnmR1nH72ZOHZhJBeoHUMizVZp37/gXfOf1x4AiUr5YMrV1/e5RWeTQjpBVrHsFirdV7e5X1w5WrhaZSsiFOHjxWeSgjpEVrHsFirder3Hzi+/8n3ks8Kz6SkFz64cpXKIaMFrWNY9ME64NThY2+8di6KE2P4nx87/Nb7HxXejH7xq7d+03yhwY41MnLQOoZF36xjHrd945Yj9+0rvBmEjDm0jmFB6+RC6xAyDNA6hgWtkwutQ8gwQOsYFrROLrQOIcMArWNY0Dq50DqEDAO0jmFB6+RC6xAyDNA6hgWtkwutQ8gwQOsYFrROLrQOIcMArWNY0Dq5fPOGm2gdQgqH1jEsaJ1cSqVS4W0ghNA6hgWto/P0todmJnbPTOwulUpYeHrbQ4W3ipCxhdYxLGgdnae3PXTD175eWoobvvZ1WoeQAqF1DAtapwPf2XifWOc7G+8rvD2EjDO0jmFB63RAyh0WOoQUDq1jWNA6nUG5w0KHkMKhdQwLWqczT2976Kavf4OFDiGFQ+sYFv20zrEHHztx4Blj+LO9/0vhbegjfJ4bGVFoHcOiP9ZpvtC4cPnLwh/PTLpz4fKXjSPHC08ihKwIWsewWKt1Xtp+8N2PPik8n5LeieLkpe0HC08lhPQIrWNYrNU6b7x2rvA0SlbKmfrZwlMJIT1C6xgWa7LOsQcfKzyBklXw4bXrR3ceKjybENILtI5hsSbrnDp8rKi8GcZxHoM76UKrtdhuD+jI6/wFnpx5sfBsQkgv0DqGxZqsM6DutSnXrTpO2bIqtl2x7arjzAZB1XGqjlOxbXilYts135/2vKrj1Hy/6jjTnlfz/Yptq4fCW+oaHASHrUcRToeX2KCRJDg7GhCnKc5Stqyq48w3m4vtdn8lNxeGWrPXgeYLjcKzCSG9QOsYFmuyzttnzg8uLcIiWlqXNT1aB4KBXUDZsubCMIzj2SAoWxaKjLJl4bBhHJctazYIsDFWor4RLeG8Nd+v+b7sOHJwaIeMCrSOYTGM1kG1AWGg7tGss9huwxxhHNejCFULXs6FYSNJsDHemg2CKddVrSOekMpJVlZsW5SjnhSCwYLqQhxhsd2eDYJ6FNV8fy4M4zSdC8Oa74vtZoOgkSSzQVDz/YVWa6HVqvm+nAi7y+mwGY5D6xBC6xgWw2idMI6lngjjuOo4SNOoaZDlpYOrHkVlyxLrhHEs1qk6zlwYLrRaZcvKWmex3S5bFjbGSm1LtT3oBMPxs9ZBhVTz/flms2xZU647GwRzYSi1FPRZjyLpzcPngg7DOEaJhgbg+JpuaR0yttA6hsWQWgddZ8jdyOzTnoeMD08ga0vxASAqVTCqfmTltOdNex70oKoI8ujYJNhivtmMlV4+1TrSs6eOJEnnntrLJ6qTvWQBDVPbLwaldcjYQusYFkNqnYptwxMYqoFvstsgTQtTriubYdgG3XQyL0Csgy4vNb93qXUWWi3MZZhyXZyiu3WkDRh8ipWuPNWFIjnZXbZXD07rkDGH1jEshtQ6ah2jWQdFw7K1Drwl3W5aZ5p2RlmJY2rvolJBBYPBmwFZZ8p1WesQokHrGBZDah30p0lCV60jmXrKdbUrdTAODzdoVQvKlI7WQVWEdN9IEvS81aMIwzAQSfzVOWzis/5aB2fHwaXBtA4Zc2gdw2JIrZOtdeCY+WYT2X9Z62AMRmgkCd6q+b52pSf2UkscXB407XnqRLIuM6fVSWjQlRwHy7NBICeVEy2221hWd8e8iSnX5Rw2QgCtY1gMo3VgCHEJ/uQXNzSSBPOSuzCIVol11DGhKdcdXCcYrUNIndYxLobx3gRkHeC9CcioQOsYFmuyzl8+9heFZ0+yOl5/9LnCswkhvUDrGBZrvef0h9euF55AyUrhPafJCEHrGBZrfb7OmfrZwnMoWSl8oigZIWgdw6IPzxI9F10sPI2S3nn7zPnC8wghvUPrGBZrtQ44dfjYrz/9vPB82l+iL74ovA395b3kMw7nkJGD1jEs+mMdcHTnoRMHnjGGm77xu4W3oY+8tP1g4emDkFVA6xgW/bSOYZRKpcLbQAihdQwLWicXWoeQYYDWMSxonVxoHUKGAVrHsKB1cqF1CBkGaB3DgtbJhdYhZBigdQwLWicXWoeQYYDWMSxonVxoHUKGAVrHsKB1cqF1CBkGaB3DgtbJ5Zs33PT0tocKbwYhYw6tY1jQOjo/r+yfmdg9M7H7m//dTX/8T74zM7H7yH37Cm8VIWMLrWNY0Do6waT7zRtuKinxxL17C28VIWMLrWNY0Dod+MFd20U5lQ2bC28PIeMMrWNY0DodUMsdFjqEFAutY1jQOp1BucNCh5DCoXUMC1qnMyh3WOgQUji0jmHRT+u8uvenpw4fO1M/awZ//sRzhbehX5x+9uTx/U8Wnj4IWQW0jmHRt2eJfnDlauHPyiTL8vaZ80d3Hio8jxDSO7SOYdEH67xz/uPCkynpnQuXvzz24GOFpxJCeoTWMSzWap3GkeOFp1GyUqI4KTyVENIjtI5hsVbrfHjteuE5lKyCkzMvFp5NCOkFWsewWJN1frHvZ4NLi40kWcvus0Ew5brqmjCOu5yiHkU1358NgsV2GxuDhVYLGyy223ir40vsUnWc7CnkUFm0jac9bzYI1sc6b7x2rvBsQkgv0DqGxZqsc/rZkwPKiWEcV2x7LUeo+b52hLJl1aNITfHTnifnqjpOzfenPa/m+9i4YtsV2y5bFtbUfB8Lcnz1ZV6bp1wXx8GhZBloTppvNqdct4uW+gg72cioQOsYFmuyzpn62RGyzrTnqdVP2bJQ61Rsey4Mtd3LliUtwfLqrKNSse2sSHAcuE2Ql7QOIbSOYTEy1pGKpGLbko7xsmLbqFqgFrWYUI/QSBJxSSNJ8G49ijqqQraU5V6so1Yz2d42tFytt4Sq40hXHrYcnG9oHTJa0DqGxchYp2LbyNeL7baUKfgXa+I0nQtDyfXo2srmfRxERlBqvq8N/2jWmXJdHLPHWqdL/xiKqoptT7muNiY0F4ZytHoUiURpHUJoHcNiNKwjpQmQ0RdMAag6DiRRdRzpK8v2sMXKFIOKbaO2wO4drQPESX3sYUMf2nyzqb0LFUnbaB1C6rSOcTEa1tFewjrzzSbyuNQ6UsrkWWeh1Spblnq0ehSpnWmqdbQ1mGugtWF11sF5NetgKsGU6w50OIfWISMHrWNYjIZ1oAFJ2ehhEw2oA/5SmnTsYUPqrzqOOkEZXV7yEgVH1jrwE95Ve/lWZ52OoGhbh0KH1iEjBK1jWAyvdaSPCwJA0sdAPbrRMDsAzhBJyGC+jMdozAZB1ihI95jcDCF1LICmPU82y057W4t1UJnNBgEKuCnXXePlSrQOMQZax7AYUuvkkc3F2cpg1fm6xx3VzRpJUnUcAYWUoM1T6GgdKFPrVcPAT0dr0jpk3KB1DIs1Waf5QmOdrTPSyI0PVLr0pw20q43WIaMCrWNYrMk6rz/6XOGpnKyOt8+cLzybENILtI5hsSbrHN15qPDsSVbH6WdPFp5NCOkFWsewWOs9p3/11m8KT6BkpVy4/OXLu7zCswkhvUDrGBZrtc7Lu7wLl78sPI2SFcHHHJARgtYxLPrwLNGXd3l8nOiocOHyl68/+lzheYSQ3qF1DIs+WAecOPDMmfrZKE6M4X/4n2beev+jwpvRL9489e6pw8eO7jxUeBIhZEXQOoZF36xjHrd945Yj9+0rvBmEjDm0jmFB6+RC6xAyDNA6hgWtkwutQ8gwQOsYFrROLrQOIcMArWNY0Dq50DqEDAO0jmFB6+RC6xAyDNA6hgWtkwutQ8gwQOsYFrROLrQOIcMArWNY0Dq50DqEDAO0jmFB6+RC6xAyDNA6hgWtkwutQ8gwQOsYFrROLn2xzqt7f3rq8LEz9bMjyulnT5448EzhvwUZZ2gdw4LWyWWN1jl1+NgHV64WfpPpfnEuushH8pBCoHUMC1onl7VYx8hHP3xw5erx/U8W/ruQcYPWMSxonVxWbZ3GkeOFG2JAvJd89tL2g4X/NGSsoHUMC1onl1Vb58Nr1wvXw+BoHDle+E9Dxgpax7CgdXJZnXV+se9nhYthoLx95nzhPw0ZK2gdw4LWyWV11jG4ew28l3xW+E9Dxgpax7CgdXJZnXXO1M8WLoaB8v6ly4X/NGSsoHUMC1onF1qH1iHDAK1jWNA6ufRinZ9X9mtrVm2d+WazHkVYbiTJXBjGabrQatV8v+b78yEYbNcAACAASURBVM1mnKazQdBIktkgqPl+I0niNF1st2eDAHvVo0iWVbBXzfcX2+2a72OlLOMI9SiSs9A6ZKigdQwLWieXXqzzo80777rpth/fs0vWrNo6c2FYdRwsT7nubBAstFply6r5PpQQp2nFtiu2Pd9szgZB2bIWWq0wjiu2jb1qvi/LKtgL1ilbFlaGcYxlLEA5ZcsS89E6ZEigdQwLWieXHq1TKpVKpZK4Zy09bKIELEx73rTnaf6QcgRm6tE6sldH68he054nxRCtQ4YEWsewoHVyueum2/7JP9g4ccsdXdj0OxtKStx1021Hj/ybVVtnynXnwrAeRVOuC1uEcaz5Q9ag561H68he3a2DY9I6ZKigdQwLWieXp7c9NDOxuzvf2/R7opzKhs1P3Lt3LbVOPYqqjjPluujmQjWT54+q48yFIa1DjIfWMSxonTWBHjb4BmvWOIetbFnigEaSlC0LalHHdcI4xriO7DIbBBiVWdY6sBpMQ+uQkYDWMSxonTXxxL17xTdgjdaZbzbViWT1KJr2PKl+MEKD8Z6FVkvkhKoIswyyx5wNgsV2W15idzGZNguOswnIsEHrGBa0Tp/pYh1MVhYwM01QxZBHdqQnyyoOuyJoHbLO0DqGBa3TZ7rXOmEcC4vttvqyl4zfi3VWcVhahwwztI5hQev0meYLjb4negFXhhYLrUPWGVrHsKB1+szrjz5XuBgGyrnoYuFfMhkraB3DgtbpM0d3HipcDAPlTP1s4V8yGStoHcOC1uk/v3rrN4W7YUB8eO36sQcfK/wbJmMFrWNY0Dr95+Vd3oXLXxZuiEHQfKFR+NdLxg1ax7CgdQbCq3t/+u5HnxQuiT7ywZWrpw4fK/yLJWMIrWNY0DoD5PVHnztTPxvFyeB49dSb//rI/EBP8eapdxtHjr+8yyv8+yTjCa1jWNA6o82PNu/8g9smCm8GIYOD1jEsaJ3RhtYhxkPrGBa0zmhD6xDjoXUMC1pntKF1iPHQOoYFrTPa0DrEeGgdw4LWGW1oHWI8tI5hQeuMNrQOMR5ax7CgdUYbWocYD61jWNA6o81KrfPS9oMnDjxDeuH4/icL/31JndYxLmid0aZ36zRfaPz6088Lv7POyBHFyeuPPlf4Dz3O0DqGBa0z2vRinWMPPkbfrJG3z5wv/LceW2gdw4LWGW16sc475z8uPGsbQOPI8cJ/7vGE1jEsaJ3RZlnrnJx5sfB8bQYfXrt+dOehwn/xMYTWMSxondFmWeu8eerdbn+/J4m2JozjwvP70MIBnkKgdQwLWme0WdY67yWfdUmjU6477Xnysh5FFdte51Rej6L5ZrNAlyy22zXf72VLPtSuEGgdw4LWGW2Wtc77ly53z/hly1IlNBsE65z0a77fY9IfEGEc9+jaM/Wzhf/iYwitY1jQOqONZp1/Zf1hMOmqG3S3TpymZcuSfrayZS20WpKIK7aNd2u+P+W6VcfBSmxcdRzpjitbVseuuWnPwy6oqHBY9Tg13y9bFtA2QEuqjjPteR2PPxeGZcvC9rJ71XFEZrJcdRxsg6JqLgyxFz5C2bJKpVLeR6B1CofWMSxondFGs87ELXd884abfnDXdnHPstaZ9jwooR5FkqYrtj0Xhmo5IrKRTrmKbXe3zlwYTrmuHHCh1UKKX2y3YQLUVWqtI8ecDQLsW7FtOYjKQqslh5oNAlVaWpulgJN3pbXYnbXOkEPrGBa0zmjzo807v/3Nu2YmdoO7brqtVCqVSiVxz7LWaSQJUvaU68I0ska1johBcvSy1qk6zpTrYl9soFkBx5QFnBcvUSRpZ1ERLaFJXaxTtqxpz5NmQLRVx6lHkfaJaJ3hhNYxLGid0eYnW/dM3HKHcNPXbywp8S/+0T/9q/90adlkCiWIabJZWLWOzDhY1joV254NAsgG73a3Dt6V7dHvl2cdmKlH69SjSG1GvNTJBm/ROkMOrWNY0DpGMXHLHfBNZcPmJ+7dW++hh03+9pfutaxFMK4TL/WwocMKdYwk/awb1HJEHS7Ks452XnR/5VlHnQchPWxqt9uU6+Jc0pUnzZDlrKtonSGE1jEsaB2jmLjlDvEN6MU66NqSHqc4TeebTQzUV2wbswlkkF/khL1kML+jG2QXpHVttB+ygT+wXiYIoE6KvzpnQQNewVQFMRBWqk1tJAk2k+JGXkq1hAZwNsFwQusYFrSOUTy97SFtTS/W6WIjzRBqrZCtHjqy7AZdzrss2RIq74zaMXs/Ba1TOLSOYUHrGM5arCP0eEkNuulAx4lnawFTt4U4TWXuQ8W21+eKH1qnEGgdw4LWMZwoXs0f9RqzQbD+V4/26CFtkvdAOf3sycJ/0DGE1jEsaB3D+eUrbxauB2Pgc94KgdYxLGgdw/nFvp8VnqzN4P1Ll1/afrDwH3QMoXUMC1rHfN547VzhKdsAThx4pvCfcjyhdQwLWsd8Xtp+sPvzDkh3Prhy9dThY4X/jmMLrWNY0DrjwvH9T7556t13P/qk8CSepR5F0RdfFN4MjQ+vXY/i5Ez97Mu7vMJ/vnGG1jEsaB1SPH9w28SPNu8svBlkOKF1DAtahxQPrUO6QOsYFrQOKR5ah3SB1jEsaB1SPLQO6QKtY1jQOqR4aB3SBVrHsKB1SPHQOqQLtI5hQeuQ4qF1SBdoHcOC1iHFsyLrNI4cPxdd7Mu9tA0jipM3Xjv36t6fFv6D9hdax7CgdUjx9GidV/f+dDivch0qPrx2vflCo/DftI/QOoYFrUOKpxfrvLT9IOub3mkcOV74z9ovaB3DgtYhxdOLdXgP0xXx4bXrxtzIh9YxLGgdUjy9WOfC5S8LT+WjhTHlDq1jWNA6pHiWtc6xBx9b55QdxnGPK4eWt8+cL/yX7Qu0jmFB65DiWdY6Jw48I3m/6jhYng0CWe4jc2FYtqyKbVdsu5EkshJrply3cJ30SBQnhf+yfYHWMSxoHVI8K7JOxbbjNJ1vNrHQd8qWhZpmLgxhtXoUDehctE4v0DqGBa1DikezTjDpPr3tIXUDzTqNJJFCpB5FUn8stFrwRNVxUAlNue5iu111nIptz4VhNjVPuW49itTjVGx7vtmM07Tm+zXfxzYd91Wp+X7VcaqOI1tiL+3UstlCq5U9SMW20Rithai0Gkky5bpSflUdB8s4KQ5L6zCGP2gdUjyadY7ct++Gr339OxvvE/do1tGyc9mysDAbBDBH2bKQ6JH0wzgO41g2U5lvNkVUOCZOoSbxim1Pe17ZsuSwWeXgvAutlkgL7Vxst3HqRpJAHthssd3OHmeh1ZpyXc1JOA7KL1mIlZqsbFmzQQA/qR2AtA5jOIPWIcWTtU6pVCqVSuKerHXU7C+1iBRAIpia7097nqTvjtMBkOhlM7hh2vPEbWXLQjaHP7JlSsW2ZaX0y6mnm/a8mu/Xo6hsWeLLehShnNLqG1RyHZudZx31y6F1GEMetA4pnu9svK+UHzd87ev+Qz9RE2sjSSTnIn2jPpCcq1oHvWRdrDPfbIoMFlqtsmWhEJHhnLy8ny221NSvbinNwHAUNkAZFMaxWvdIuSMqonVoHcOC1iFDh9Q6pVKpsmHzE/fu7TibQC07KrZd8310NK3UOqiccFj4TASAZXVcB31l2SOgVw1lDcoUdaXWJVh1HGlVturSSh+12TJutNhu0zqMEQ1ahwwdsA58gzVZ68Aosoxxl2zxsax10PeFjI8FTI/GwbEG+pn2PG3gREDXGXwjTUJNgyEfrJwNApxO7WdTyZOirIdrMSWhVCrROoxRDFqHDB0/r+wX3wCxDsoRNU1L95S2HguL7XbHDTomerXLbi4M1e0XWq25MOxylSg2UF0CW9SjSF2JI3ecwJaH1mzMSlBbq7ZK3ZjWYQxn0DpkBFCts0YwOQ2s7pLPRpKoB8mbVJ3Xobdu0DqM4Qxah4wAfbTOulF1HFqnL9A6hgWtQ0aAV/f+tHCLjBy/eus3hf9wfYHWMSxoHTIafHDlauF5fLQ4/ezJwn+1vkDrGBa0DhkN3j5zvvA8PkJ8eO26MY+ypnUMC1qHjAYv7/JY7vTOL195s/CfrF/QOoYFrUNGhhMHnuGz3Xrh7TPnX9p+sPDfq1/QOoYFrUNGiaM7D/3ylTff/eiTwjP7EHLh8pfnoouvP/pc4T9Tf6F1DAtah5DVMzOxe+KWOwpvhtnQOoYFrUPI6qF11gFax7CgdQhZPbTOOkDrGBa0DiGrh9ZZB2gdw4LWIWT10DrrAK1jWNA6hKweWmcdoHUMC1qHkNVD66wDtI5hQesQsnponXWA1jEsaB1CVg+tsw7QOoYFrUPI6qF11gFax7CgdQhZPbTOOkDrGBa0DiGrh9ZZB2gdw4LWIWT10DrrAK1jWNA6hKweWmcdoHUMC1qHkNVD66wDtI5hQesQsnponXWA1jEsaB1CVs+KrHN8/5Nn6mfPRRejODGDd85/fKZ+dtDPkaN1DAtah5DV06N1Xt3703fOf1z4w0YHx7sffXJ8/5MD+pJpHcOC1iFk9fRinZd3eR9cuVq4GAbNh9eu/2LfzwbxJdM6hgWtQ8jq6cU6v3rrN4UrYX1496NPBvEl0zqGBa1DyOpZ1jrHHnwMGXmx3V5otdQc3UiSwj3Rd04ceKbvXzKtY1jQOoSsnmWtc3LmRaTjuTCs2LaaoMuWVbgk+s7pZ0/2/UumdQwLWoeQ1bOsdc7Uz6qakXJnLgyrjlO4JPrO22fO9/1LpnUMC1qHkNWjWeeJe/c+ce9edQPVOlXHmQ0CWZ4LwzhNa74/5bpVxylblrrcSJIwjqU8qth2GMdqfq9HkbzbSBIsz4Vh2bJwBPXgFduWjaXGCuO4Y72FvdCequPIecuWheWyZU17nrST1mGsKGgdQlaPZp0fbd5ZKpUqGzaLe1TrqJ6QdI8UH6fpQqtVtixoadrzpj0vTtMp150NgtkgwEuNim2jeJr2vJrv4wiqnGq+L2eccl0cpBfrVGx7sd3WbKdapx5F2FKr2GgdxrJB6xCyemYmdt91020zE7vB9zb9Xmkp4B7VOvFSJ9tcGMI0SNw1389WIbDFYrtdtixtQEiY9jxYCvqZDQI5bPbgcsxerCN75VlHOyatw+g9aB1CVs+R+/ZN3HKHsOl3NpSUuOum206+eEpNyqhdqo6DWmFZ6yDv5807QMdaI0lQcNR8XyuJ1INLpUXrMIoNWoeQvoEeNvjmx/fsqn+1h01Sv5rru1sH1Qw60DqKp2LbU66LIaJGkpQtCz1jcnCpfiA8tX9sNgiWtc6U62IZiqJ1GGsPWoeQvvGjzTvFN0CzTrw0FL+sdTCMr44Ddby+RzPHtOehRw47YoQGswlkAEZmHMikgy7Wgcmwe0frcFyHsdKgdQjpGz+v7NfWZK2zDoifxB/aBaorpffdaR3GskHrEDJATj97so8uQYEC0KvWHbVq6eNhu/DGa+f6/h3SOoYFrUPIADlx4Jm+lzK9g1nX63nGU4eP9f07pHUMC1qHkAHy0vaDH167XqB41pljDz7W9++Q1jEsaB1CBkvjyPHCZbA+/PKVNwfxBdI6hgWtQ8jAORddLFwJg+bdjz55afvBQXx7tI5hQesQsh6cOnzs/UuXC3fDILhw+cvmC43BfXW0jmFB6xCyfry8yztx4Jl14J//y++uz4kGMZCjQesYFrQOIQZSKpUKb0O/oHUMC1qHEAOhdRhDG7QOIQZC6zCGNmgdQgyE1mEMbdA6hBgIrcMY2qB1CDEQWocxtEHrEGIgtA5jaIPWIcRAaB3G0AatQ4iB0DqMoQ1ahxBzeHrbQxO33DFxyx2lUgkLT9y7t/BWrRFax7CgdQgxisqGzaWluOum2wpvz9qhdQwLWocQo3ji3r1inR/fs6vw9qwdWsewoHUIMQ2UO2YUOnVax7igdQgxDZQ7ZhQ6dVrHuKB1CDGQ3f/4/sLb0C9oHcOC1iFkeY7vf/KN1869+9EnhT9CzTzeSz5789S7rz/6XN6XT+sYFrQOId14afvBX77yZuGpeRw4F108uvNQ9iegdQwLWoeQbpypny08HY8P56KL2Z+A1jEsaB1CcvnFvp99eO164bl4rDg586L2K9A6hgWtQ0guzRcahWfhceNXb/1G+xVoHcOC1iEkl3PRxcKz8Kiw0Gr15TjvX7qs/Qq0jmFB6xCSy/uXLmfTYs33sdBIkoptg6rjYOVsEFQdp+o4WKkuLJtw61FU8/3ZIFhst+M0DeMYNJJEtmkkSc3358JQ1oRxPBeGNd+fct2Ohw3jWNosH0Fd00gStXl5TQ3jOO8UcZpWbBvN7vihwGK7PRsE8jL3e/jqr0DrGBa0DiG5dLTOXBhWbBtZeNrzIIayZUlCr0dRnKbTnoeci4Xu1gnjGHKq+f605yEjly0LSitbFg6C40Aw0oaa71cdBx6CCMV2jSTBlmXLwkpQtiyswTGnPW8uDKdcF3pTm1rzfTmgalAcBBtjvXYKII6U76rqOPjG0H5aZwyD1iEkl47WQa5HsoZgYAipdaANuEH+ru9unYptq+WLdsx6FMmy+i6aATdgWS1rOq7sWOtAABXbDuN4sd2u2Pa051VsG5vJx4GBsICSTo4w5bryVWjIEeAbOQKtM7ZB6xCSS9Y66CBabLe1vDnluig4pj1PKFvWlOvKSyR6FEZSLoRxXI+ijilYTNNIEs06i+021syFIY6DKgRdbVnrZGsddbOKbc83m1IAoVWyO44w32yi8EIxp3X64dQdTzEbBKh10DaRVpfOOu1XoHUMC1qHkFyy1mkkifSqqUUAVKSaCdlctpFSoGLbWIYMkN87pmAkbhxHKqHZIED2V2sLqXvyah3poIuXutSwGXyGo6HWiZd62GR3CFWqGfTFaeNAWqEz7XnyiTQVSZ8hjknrjGHQOoTkkjebQLLzfLMJA2EMQ83CMhcgjGN4KFu1iHU69r/BOlOuq2bnxXYbdUPFtjFtDFoqWxZKihXVOo0kQePjpR42sQ7kKg1Qazj0v0173nyzWfN9ta8Pu88GgfZZMBMB/XLZvkRaZ6yC1iEkl+7WqUcRfCCJe1nraKPo0sOWHbaJlR62jnkc9QqGYVBLwYKrGNfRrCMT81C9qZPQpKSTz1t1HExG0AoaLKOEgqLEylAmVtI6Yxi0DiG55FmnHkXQAOYLYLaYbCAD5oL0aMVf7Q2T5YptawVNnBnX0eYlo1us5vswTV4Pm8wxU+e2yUt10ppW68RLswxkEprMQ4sz89zUWkeOI+/iXFivTYGjdcYwaB1CculoHfQvoZtoNgjQeaVeI4m/4lUgJ/lLH9XAlOuqfVNSJZQtC0pT8zK6uWQYRisUOnamaZPc1OpEJkl3rHXwFqqoWJmEJvPQVmodvBQLqieldcYwaB1CculondkgwF/9qGmky0guT+lY6+A6GzkILJX9e1+VQR7ZbbrUOmo7/z6tRxHMpHaXYZaaemkO9qpHkepUTEXraB3UXmXLUreXWgcWlFOw1hnboHUIySXveh0kXz1X5lywojHfbC60WgutljYTbC3Uo0j637SF+WZzWXstO7yvstBqhXGsekXOjpkOmhS19si7Xfyq/Qq0jmFB6xCSSxfrrBr87Z+tPwitMyZB6xCSy3vJZ4Wn4HHjw2vXtV+B1jEsaB1Ccnnz1LuFZ+Fx492PPtF+BVrHsKB1CMnl1OFjhWfhceON185pvwKtY1jQOoTk8tL2g7/+9PPCE/H48OG16y/v8rRfgdYxLGgdQrpxfP+TfIj1unHq8LHsT0DrGBa0DiHL8Oren7770SeFZ2Sz+fWnnx/f/2TH75/WMSxoHUJ64tiDj/3lY39xpn52JLhv4r7C29Ajpw4f+8W+n3X55mkdw4LWIcRASqVS4W3oF7SOYUHrEGIgtA5jaIPWIcRAaB3G0AatQ4iB0DqMoQ1ahxADoXUYQxu0DiEGQuswhjZoHUIMhNZhDG3QOoSYw88r+2cmds9M7C6VSlh4ettDhbdqjdA6hgWtQ4g5BJPuN2+4qbQUN3zt67QOY9iC1iHEKH5w13axznc23ld4e9YOrWNY0DqEGIWUO2YUOnVax7igdQgxDZQ7ZhQ6dVrHuKB1CDGNYNK97Ru3mFHo1Gkd44LWIaQnju489PqjzxV+h+YeOXrk3xTehh45OfNi9kluKrSOYUHrELIML+/y3jn/ceFPoDGbdz/65NW9P+34/dM6hgWtQ0g3frHvZx9cuVp4Uh4HPrx2/eTMi9mfgNYxLGgdQnJ5afvB95LPCk/H48OFy19me9toHcOC1iEkl1OHjxWeiMeNX77ypvYr0DqGBa1DSC5vvHau8Cw8bkRxov0KtI5hQesQksugu9fCOFaR9Y0k6e+JGkkyGwTZ9fUoWmy3u+xY83315VwYqi8XWq16FOW9uzo+vHZd+xVoHcOC1iEkl/cvXc5LjlXHqdg2aCRJI0nkJTL1bBDIGtlM3T2M46rj1HwfVGwbb025LtJ3I0mqjqNRtqyyZSHFa+vVl3NhOBsEcvBpz1PPJQaq+T5sp+4uHwFnkYbVo0iWZXfVNFXHUQ2EQ+G8+AZwFrS/C9qvQOsYFrQOIbl0sU7ZstQaJYzjim3jZcW2pz1vsd0O4xhZWytl5sJwynVlS1C2rMV2W5TTEZgsWwkttFpqxpf6Rlo4F4bTnicvG0my2G7XfL/qONOeNxsE6u5hHMM6okMslC1rynVVaaH9skZrAz6guE1eZptK64xV0DqE5NLdOh0zbJdltSaAErRaR0oHrV9LaqAp19W8gmJCyggswwFqqaRugEpI2jYXhmhJnnVQKpUtSyuVFlotEZLoRO1wU62DxpctC4eidcY5aB1CcllprSMViSTxrHWQrPHWfLM532yi7pkLQwyxzAaBZhck7mnP01ZqJ5Uts9KqR1F2d3yK+WYTVYvqGO0IHd0pH1MqrarjTLkulhfbbanzWOsw1KB1CMmlu3UwVoEcGsYxqgH8RS+dYNl8Pe15KDVmg0C610A9ikQ52qAOhnPUNdrBJZWLdZbdHdqoOk7HHrZ6FOXVOjXfX2y38fHjNMUYkrQBsoHnZC+O6zAkaB1CcllRDxsyrDYqk7WO+lKtMNDxJcrJ1jrZCkY9uCxkt8RhVS3h+Dg7Si4ZfELVBa/IGqi0HkVqeTffbEJOVcdZaLVU8+GlNK8eRQutlrxcdqqb9ivQOoYFrUNILqsb1+myXryStY66GQZ+ereO9Nplt5xyXbyF0gojSdgFdoFCuvew4d1sv99Cq4XyRZrdsXmYTaeWPt2na2u/Aq1jWNA6hOTS3Tpqd1OP1tHG21ErSM0hnshWAx2tEy9VRRirx3EwPy1e6uma9jx1TrZmDjlvx9kEohy0J7s7vgdZqVlnvtmEk6SEyk7no3XGMGgdQnLpYh1tkGOx3e54Gaa6Xq1IVCHJtTsYLNGUA4VgfnP2+KIWaZV6wZD0a8E9jSTBBlOui8N2r3VwcLU9cJuswTLmc2Num3TBoc9QXaNap/tlsNqvQOsYFrQOIbl0sc4qUK90QSmACWzijKrjYEaZCoZkKraNwRJ1d/hDW4+LfqSewKwEzWRSb6m1jjaugy417eDYF8WNdljZSyvL1FkJ2ctUaZ0xDFqHkFz6ax3SI9qvQOsYFrQOIbnQOrQOo+9B6xCSy7noYuEpeNy4cPlL7VegdQwLWoeQXM7UzxaehceNc9FF7VegdQwLWoeQXI7vf7LwLDxunDp8TPsVaB3DgtYhpBtvnnq38EQ8PmQf6VandYwLWoeQbry0/eDbZ84Xno7HgXc/+uTYg49lfwJax7CgdQhZntcffe6d8x9fuPxl4am5R05cHJl5EB9eux7FSePI8bwvn9YxLGgdQgykVCoV3oZ+QesYFrQOIQZC6zCGNmgdQgyE1mEMbdA6hBgIrcMY2qB1CDEQWocxtEHrEGIgtA5jaIPWIcRAaB3G0AatQ4iB0DqMoQ1ahxADoXUYQxu0DiEGQuswhjZoHULM4eltD93wta+XlHji3r2Ft2qN0DqGBa1DiFF8Z+N9opzKhs2Ft2ft0DqGBa1DiFGo5Y4BhU6d1jEuaB1CTAPljhmFTp3WMS5oHUJMA+WOGYVOndYxLmgdQnrlpe0HTxx4ZiT4yR/+sbbmgc3/7MSBZ5794U/273DU9S8/7Gtb7t/hZFfu3Pr73c9Yq+6T5R8+8Ic9tnPn1t8/uvNQ96+d1jEsaB1Clqf5QuNfP/3n056nPo6s6jgLrdaU6065rvaksqrjzAZBnKaNJMm+G6fplOuqR9M2k5ezQVB1nMV2Wz2yLNejqOo4ZcsqWxa2n3LdRpLIBrNBgGbEaVq2rDhNwziu+X4Yxzhyxbbnm021YdOeV3Wcjp8Iu+N0grRHFnCEmu/XfL8eRXGazoUh2lmx7arjVB2nkSRzYSh7/frTz3/5ypsvbT/Y8cundQwLWoeQbry8y3v3o09gAiRuEQNeVmy7bFlIryKDsmXVfB9pumLbWesgZctLbTN5WfN9MYoqjzhN55vNsmUhd+OkaEwYx7IxUv9iu43j1Hwfe017Xj2KFlotiErdXuyliUe1Hbwl7VSPX4+iKdcN4xhvydey2G7jE0mDcUD1sBcuf/mLfT/L/gS0jmFB6xDSjV+99Rs140sanfY8FCsV2572PDVH48/5LtaZC0MUBJKCu1in5vtq+hbrqCuFjtaRGiWM43oUqTUWqiVYAaapRxGqH7QQZoJUpExRraN+TDENaqlpz5PG4Mg4LMqvrHXiNH0v+Sxb8dA6hgWtQ0gurz/6nJoTpRRAfkdGRrYVGSy0WhXbVtN91joV224kiWT8Za1TjyJ5FyfSCi/1yHNhiFIjjONpz0MzVF3VfB/+qDrOtOc1kmS+2cSOavOknKr5/mwQqD7LWkf8UfN9nBQ7Vh0njGMcR05atqzFdrujdeI0Pf3sSe1XoHUMC1qHkFx++cqbakJcaLUk6YsGkI4lv0+5eV04YAAAHglJREFU7lwYdrEOtCQmgLq6WweHxYIMz3TsuKvYtop09KHlU6670GrhmAIGjRpJIq6aC0PUK2Ecy5CSqge4RKt1cHwRkkhIrb3gbBQ9edZ55/zH2q9A6xgWtA4huURxkk3r6KSSUXpYBy6R0Ysu1pn2PIyrq1ZY1jqL7XbZsqTE6VLrZHvYcDT0sEGQajGE7VHNaJRKJZmbIB1xUqbEytwETEwQzSy22+jHw8t6FKEl+Lz4RHnW+eDKVe1XoHUMC1qHkFzev3RZy4mzQTDlutK9piZ6TP2SbJtnHUwBkKqio0WkK0+OEyszweS8Yr7u1pHzoj0ywUx6wGR7daBI7XPDp5sLQxm8kW9D7WHDBjAQutTwcrHdlvkFWOhinTiThWgdw4LWISSXrHXQVaXmSkn0mLomw+9q15NkeWyjSQj1BKRVj6LZIJCVqjawjeyOI6NYwfSEHq3TsdaJl3rA0AunKQe7Y3KBekx1WeuCqzpOdrKDuo18alpn3ILWISSXrHXwB76aT2eDQAY/pPioRxG2waxi1Tra9THzzaYcDdfQ1HxfCik5jjhPlRBeYhdspjZG272XWidOU5Rf2pVJaCfeRZ2HgR+RnHS7YeIDjIVZFQutFkqiKdeVS3wwjCQdkrTOWAWtQ0guHa0zcjSSBNPV4uVqnXipisIYVfZQYilIS66ERfcarKlepoopbbNBgE5F9VBTriutonXGKmgdQnIxwzojh/Yr0DqGBa1DSC60Dq3D6HvQOoTkMgzWmQ2CRpJ0vJ8b1mhDRzK2lL2Es5Ek2WlvcqgwjrXbuNE6jEEErUNILgVaRy7blGEYmXYsAyRyR051qEa7mGa+2cQVQrhtD+7fI7MVBFxYo+5O6zAGFLQOIbkUaB3M+5JpZtoMbLl2B8P4WevgNmhy62tURbg9Wrw0/q8iN4Su2HbHm2TTOox+Ba1DSC7D0MMmVYg2yVjWaJOhsRI9crjNmiaYjtWMdusaWocxuKB1CMllOGsd1CvoN8OMZO1KUiygdomXrpvRtCS1EVAHhApH+xVoHcOC1iEkl+Ec15Gr+nE7A9zLAHdOk1IGz7kB8vQB3BJNbkWDO61hL9wqrXDf0DrjELQOIblk7/65/nTsYZsLQwztxEuzBrAG26NXbb7ZlPtsombCjbHVHja5vw52KfzDxrz75xgErUNILm+8dq5A2XSZTaA+LEB62FC1YHm+2cR63CFbtQ4eJKpZB7uLgQq0Dp90YHzQOoTkoj3VbT3RblrTfeY0bneGm6SpR8Djc/BcNXTBoattsd1eaLXk/qG4c5o87rPjvdHWjeYLDe1XoHUMC1qHkG68c/7jAlNwnD+HTayD+1jjgQIQD+QhNkKhg4EiCAZPpZOHsKG4wUrcS62oD/v+pct8grXxQesQ0o2Xd3m//vTzAq2z7L0JUMrISmwcL92JAEM+2gGzV4kCzDUoqoftwuUvj+9/MvsT0DqGBa1DyDK8tP3gL195cxiu3emd6IsvCm9D73xw5eqbp949uvNQx+9/hda5lqafFf2BCPgsTa/SOoSsnpd3eScOPDMS3PSN3y28DT1y7MHHun/tPVvnb9L0ZJrWh4RW66k4frzVempwp8g7/qDPu0JOpunf0DqEGE6pVCq8Df2iN+v8n0Xn1q/4xnEmbXsLcJzJVR+q3X4+Seay6z1vl2VtzB7f83bJeeP48cK/CoWPaB1CTGbMrHMlTY8WnVX/HtveEgT7VAmt+lC+v8f392SVY9tb2u3n8dJ1d0A8cfy4ZW0s/OPncDRNL9M6hBjLmFnnXNEp9e8Jgn2uu6PjelGR6+5Qlx1nUnZpNmuOM+k4k81mLQj2WdZGy9qoVUuWtVEzmWVtTJK54bZOPU3foHUIMZYxs86JovPp36MWOnH8eBw/ji4ytWqx7S1YdpzJMHwE7vH9Pa3WU5a1EUVMksy128973i7P26X2lXVUi21vkePI8vDxCq1DiLGMk3WuFZ1MOwsAUsEQS0frwDEwUxg+gs0sa6PqjGwPW3frpGkdh1rLYNIguULrEGIm42SdK0Vn0q+A6kSVRJ514A+s9/09qJCSZM5xJmGjjtaBmbJrtEkHjjOpji0NDbQOIYZC6xRFFM2IM1TrqOM90sMm/WkaQbAv6yrVKOrQkWys4nm7sjsOAbQOIYZC6xRIGD5iWRsxVCOdXehP87xdrrsDJU66NBvN9/dg4zh+XPbCBuguU4sn8Ra2QSceCh0YTk7Rccp10dA6hBgKrVMsrdZTUTQTho+oEwFarafC8JFW6ynMFMDKJJkLgn1qbRQE+1RhYOAnewpsqb2Fo0XRTOHfAK1DyHhB65ChhNYhxFBu+8YtJcaoxc9//oOirUDrEELGnjGpdV555Uf79/9B4c0YMLQOIWTooXUMgtYhhAw9tI5B0DqEkKGH1jEIWocQMvTQOgZB6xBChh5axyBoHULI0EPrGAStQwgZemgdg6B1CCFDj/HWef31P/7TP909NfV7lcpdf/qnu//sz5zCmzQwaB1CyNBjvHVOn/6xeoeCQ4e+U3iTBgatQwgZeoy3TprWK5W7oJzf+Z0bPv/86cLbMzBoHULI0DMO1pFyx+hCp07rEEJGgHGwTprWK5W7TC906rQOIWQEGBPrnD79Y9MLnTqtQwgZAVZtnd+mr/yX9I1LaTwq/McvosLb0CN/m577u/QkrUMIMZDVWefz9IN/l/42TlMyOP5zmvw2fYXWIYQYxSqs85/Svy48I48J/yG98t/So7QOIcQcVmqdv03PFZ6Lx4r/nCa0DiHEHFZqnf8rvVx4Ih43rqUnaB1CiCGsyDq/TV8pPAWPIX+bnqN1CCmeNx597lKcrAMXF36tvvzotXOFf/Y+siLr/Nf0dN9Tas33sbDYbtejKLvBYrs9GwTrn+sbSYL21KOoY8PWjUtpTOsQUjzho086jqP+/+V5XrPZDIJAW4+3XNfN5tQgCOylyNtAO9qlOCn8s/eRFVnnSnq27ym1bFlYCONYDKQy5bpzYdhIkqrjqDSSRLxVse2yZVVse9rz1tKYxXZblqc9by4MpWHzzWbVcRZaLTSpYtsV2646zmwQSJPks9A6hBhIdPiYZVlJksj/X5ZltVot3/cty/J9X/1fz7Is27azOdX3fc/z4jiO41g9VMewLIvW6WMyXWy3a75ftqya79ejaNrzqo5T8328FOVMuW6Xg1QdZ8p1IYOFVmu+2Vx1e3BqeVmxbU2HstBIkprvT3teGMdopDSG1iHEWKLDx1zX9TwP/3NFUQSv+L7vuq7qGN/3HcfJs47qp3a7LS+jKGo2m+12OwgCbAmZnaqHhX/2PlJsrRPGcdmywjhebLfnwhB5fNrzkNznwhAJPS+bz4Vhx7fUPrHZIJDluTCs+T4qGFgKpkFnGuoVnBr1k+yFegumwe5S9yy0WtIG2WXQ1vnii5/TOoSsN9HhY1EUof5I09R13TAMRSSO40RRhLds2242m8vWOu12O01Tx3FwHNu2kySJ41hkRuusTw+bVnNMe95sEEinljDluiIJDfUIFdvG8rTnTbluGMcV24Y5ypY132zWowj/inUW223019V8v+o46L6r+X4YxyhuFlqtim2HcdxIErVjcB1qndOnf1yp3PXKKz+idQhZb6LDx9I0lU420Q+sE0URxmPCMHRdV+SRpqnanwaXYFwHNU2r1bJt2/M8FD3qjuxh67t1FlqtsmWhG61i25g1oJYjc2EILSG/h3E8F4aS8Su2LV1qZcsqWxbyfkfriN7qUVSxbZwa9YrmKhQ0qkK0ImbKdeEhtAQDPBjX6d4fuBbrwDe4eTatQ4aa/75sT9xyh3n8yf94KE1Tz/M8zxPHpEqnmW3brVYLRY/IA31ovu9Lv5k2AoRjisOy1vlg8f3CP3sfqWzeurNb/POdOyeEf/m9+9//u7/rVzJFvkYPW5ymqCrQ64U1880mNsjuJdlfrXXkrax10JUnw/5wA5QmdpG9MKegu3Xwbra4GUS5879/ekZ8g9i6dZP6u+zcOfHpp0doHTIs/MFtE9/bVJmZ2G0Y//ZPfp6maZIklmVJ95oqkiAIZIBHlYcaWeu0223bth3HgZay1vnrDz4q/LP3kT/f/ydRt/hfo2hG+PXF5/qeUkUqKFwgkprvL7RajSRBZ1eedVD3dLSOTGaDdVDZdGyAKETr2VP9IcM52rs4uIBuur5/RZfS+OLFJ/bsqYh1fvKT76m/S6VyVxTN0DpkWPiD2yZ+tHln4c3oO9FS15BlWVKaaCKxLAs26mIdx3HU6gcCa7fbmBGnWafZbL7XeKvwz95HhmRcR83XGCmRl12sEy9NYp4LQ0xDwFuNJMGYzWwQlEoluAQlDvroMBUbe8k0OYweydQD1R+Yt42zq1VO1XHQ7wdks75bB9+/uEfrYdu5c4LWIUOE8dbBNTryfxn+RMeyFEAyFU2LKIr8pQiCQN2s2Wyqc9iwhrMJBmEdFDRy/Q1yt6hFrLPYbsu4jnoETH5DkSTjNCib5sJQncOGa2tkM7hNvQRVLXc0f0y57mwQyAbompOWSNsGN64jXLz4xMWLT9A6ZHgx3jrrHJxN0C9gl2nPm282tf4rrNSsg2Geim2vz50CslUL6iq5UBTCE59hToG4c3DWyULrkOGC1ulv0DpknaF1yMjwwD+8Z+KWO2694aZNv7Nh4pY7nDt/v/Am9RFapy/QOsMPrUNGhh/ctV2dbfnEvXsLbxIZNlZknWvpicJT8BjyN+n7tA4ZDYJJ95s33ATlVDZsLrw9ZAhZ6fN1/n16tfAsPG781/Q0rUNGBil3WOiQjqzUOv9P+lHhWXis+Dj9YtmHWNM6ZIhAucNCh+SxUuv8t/Tof0ivFJ6Lx4R/l/522UKH1iHdeH7y4fU/6Q/u2t6x0Jn79g+HsLVknVmpddK0/nfpyf+Y/r+FZ2Tj+ffp1f+SvrGscmgd83l5l3emfjaKkw+uLNPBrT4VCleQ4UbuuK877hUoyJNF5DI07Wa6uJQa67PXK+BGufISVw/I7RTjpXvCq2vUa7+zj6WSO+lqj9Kq2HaPVySo1/31yPuXLv/qrd80jhwv/FceH1ZhHfD/pe/9dfop656+czG9lqSXLqXx9TTsRTm0juGcOnxsWdmo4Io2JGt53KGkfrnHBm7pIU7CBc9yP3aAS6PjNMVB1LPMBoHcQhH3AsGdP8QcuFOIugZnCeNYfTqINEl92Il2rZzcmXFZRDlozIr+x3sv+ewX+35W+M89DqzaOmR4oHWM5cSBZ1b6Z8tiu41bZWi1DjIybh0IJTSSRO5XiESPu3fIoeSu7ChN1HJHu3Fv9iHzEIzaKvUZjtlaRx7sCJ+ptY6cKF6q4WRZji/+w7/Q50rrnguXv3xp+8HCf3TjoXUMgNYxk5e2H3z/0uXekyayLW4mKI/mnfY8IDesVe8rhZX1KEI5ot4lV703Im5rKC+llkLh0vHGuhCb+igR9eEi2Von/moPm5Qs2FFMhptfYQO557zc7hdNwpNI8FWs1NlvvHau8N/deGgdA6B1zOT4/idXmjSle2qh1cJ9bdE91UgSlCOadfDvtOdJWVB1HHSy4T6GYh1sLM7AU6rU3rmO4ilblpRTUsRgFxlPUp8VP+W6882m1DqygL4+9U7yuCM9uhPlCFJgaZVW73xw5Wrhv7vx0DoGQOuYyelnT64ib0odMOW6cI+af9UeNphAe4KhvFQrGCxjRzxJVzI7Hl2V1xg0QO7QDlvAebhXbhjH0KE4Sa2xtIdcqc9PxIfCM7Lkpo1rt06cpscefKzwn95slrPO1TQ9O0wsc+XKeELrmMnbZ86vzjroMUOhg6GUmu9nZxMstFro9dJuvqv1p6kGQu2C7SWzly2r+x15IQlVb+IhGYPBWJT0sKHN0vhYKcJUoE/1GY5rt86JA88U/tObTXfrxHGsrcGTv+M4brfby24s6yW6Gq6XOFF4ih9CaB0zWbV1tOe916NIOtnkER1I6NLZpR1Bm8wm1sGQiZbi1YJjodXCwmwQoNcOJ1VlIwvYUYZtYB0oUwop6cHDZ8FcbbRNqiKZWq1aZ77ZVCd20zrDQ3frWJYlDytKl54XjvXyyHBEGIaWZXX0imVZ9lJAWtmIoqjZbNI6tA75e1ZhHdQuMkcARhGFzDebSMoyiRkVj8yQBlqho9pCnfY25boyGiRPmxeH4bxojDpoJMZC+SUPVRTroNstax05pkwTkAbgaVramtXNJqB11oHu1vE8z3Vd1R/QBkSiKsRxnC7WWVYm2UeJ5wStQ+uMDauwDqwA32BcJ07TxXZ7ynXFFsjvMIR0Q2kToweEzHRQu/XwdEWUMupcu+x0g/WB1hk03a2TJIk4I0kS9WHeYRiKkPCWbdu9WAcPBXccB7tAOdZSpGnqOI7neZZlqc5bOh2tQ+uMDavrYevdT+uZygs8Ka0zbCw3myC1bRudbJ7nycO8Lctqt9siIdd1wzDsYh0IBp1ycRxjdwgGx1RrHdu2IZtWqyXGchwniiJah9YZIwZqHZLH3J5HZyZ2k8Hx5/v/JMqJCxcupGkaBAEcYNt2q9VSyxfXdeEMvBTrOEshG6uzCVDr4C2RjWYdsdeSbFLscuGCH0UzRKNSuYvWMZBhs446K0ztH1O3qUdRl566xXa7x3682SBQrzDNnhfnWt18gS5EX3zxe3dtnbjlDjI4Kpu37syJP/qjP5KCQ1WFaKbVatm2LcJYUQ9bj9ZBx1oQBHj3j/6ounPnBNH43ve+/fnnT9M6pjFs1pFbAMRfvY+nuo1ckaPdwVO81fH+nnIrNplBgIkG8hJ2wWWkantEhI0kwdQ7GSKSi0xXOouaPWyDZtkeNmhAusI0kWASAWqgQVgHL5Uyiz1sXaB1zGLYrBMvTctW7xpQKpXkShptvnVHaeFaHG2CAKyDC3QwS00DU+xkd5kmp+kEChS3ycWttM5Q0Yt1giDQzCEvoyiSnjTHcfKsI4F+NtlFZBNFkczG1o7juq4yS5vWoXXGht6tg4tj5NEDc2FY830RwEKrhUwtvVuyRob3Z4NA3QXJGptl7+wZd6p1cAcd3AKuYyNRqXS8q7RYR/rrGkkiPWzSSJnYBmll2ybWwXS4Uqkkt76mdYaHXqxTbGCqwtIrWofWGRt6tw4KAlgH98eUZxmID3B/M7mH9HyzWY8iXNGJfWEF6cKShxfgXZQ48m7WOhAeUrw8Z0ErViCD+KsTo1WLqLfqgYFw45x46XkK8nnV7eUiJNwEQW5mylpnOBlm67TbbdRAyjpah9YZG1ZkHbkXmXrTaLUjC/eekbtESyWh3vcs/urTDbLHwZMI1Mf2lEol9bJNbCnjMbjdNQZmZOhF7szWsdbByBBai2OiRMNeqIFke7kRHMoy3HBB7h+K3j/1QQm0zjAwzNYJgiAzVkTr0DpjwxuvnevdOurf+zJEDxmgIMDNbNR72GT7teKv3l0tXuoZU62DMX8cShZwdSo8pDZMPXjVceabTVgBd54WpCX1KJoNAnmUnJQ1cZqiOJv2POkJlCJGDIpdZKacPLlnRVPdju9/svCf3myWs85v0/TSMNHr4zXHElrHLP7ysb9YqXWyT7tRnaGNcKB60O45na11NOvESq+XVhJln3qgWgeSwMuOPWzo0JMqR7v/tHwEOWPebAL0sKk3D13RbRf4YLdBwycdGAStYxbHHnxspdZBskb6ngtDPE8TozjyzGnMbFZHcfLGdTTrLLbbVcfBkw608iLrp6x14k7PbVNlJvvKHAFtgkO8dGdS1C6adRbbbYxFwX9qQdZ7rfNe8lnhv7vx0DoGQesYR49DO7NBoCZWPIgak9DipZtjzoWhbIZbn0lyx+OltQdRiy0W2215SgIOi7uIArmqRrMO7nuNDrGsdbK1DsoaTCIQ8GAFKVYgRYwzTXvebBCIYGTWg9pxJ9bpfVzn5MyLhf/oxkPrGAStYxxHdx5a0UOsB4c8wgDTsnFzaJmihgpJnRKNYR7URh1rHW1cBwqRZzRowHzqJaLSjQbkLDBoll4+49tnzhf+i48DtI5B0DomcnTnoSG8XNQwPrhy9dThY4X/1mMCrWMQtI65HN156PVHnztTP0v6y+lnT3Kq9DpD6xgErUMIGXpoHYOgdQghQw+tYxC0DiFk6BmQddrt5+P4cXWN9nKlJMlcHD8O+pipW62ngmCf7+9JkrkByaDVespxJgfsG1qHEDIiDMg6vr+nVCo1mzVZY1kb15JSbXsLsKyNtr1lRfu228/7/p7s+jB8xLI2et4u399j21tcd0cfHRAE+8RkHc9O6xBCxpHBWcd1d6imWbt1UOW0289b1sYVVTxx/HhWVFE0ox3HtreE4SP9coA0eB2hdQghQ8/grOP7ezxvl+ft0qwDBzjOpG1vkSIANYfjTFrWxo6dXWoSl23C8BE5VBTN4F3P24WqyHEmW62n4vhxy9pYKpU0x6htAzhamtYdZxKNUQsgtdmt1lOyGQ6rnhRv4Yx4KZ8922D1sCut4WgdQsjoMVDrwBYwhGReSbioWuRdrPT9PR1HQWx7C7rCHGcSJmi1nrKsje3288jdOH4YPiK7B8E+LHesdbKVjRxElY20VrQXBPvwruYkzY6aJvMajAWsdJzJINhH6xBCTGbQ1mk2a8j4SLJJMqcKACJJM5VQmtZdd4fjTDrOJLQE66CkEKmoxQqyvONMStEjh82zjpbiZTNVGPggSTJnWRulgMtu1mo9BSNKRZW1TscGq22TL43WIYQYy6CtA38Ewb6OAuhinawkkMQxYoSFbBJXu9q6W0eOk12jCgMtxBFkEp2IEJuhiGk2a63WU11qnY4NpnXIanj83u+Dp7Y91MfDzkzs3nPnA4/cXR1cy2v3fHfXt7YV/gWSAlnOOtfWbh0kZfGKOr6i9rD1aJ10qdcL9YfWYSXdX+lyPWxolXSy4QiiEymD1BZKA3BSaZJ6/C61TscG99U6V2mdseDxe7+/8cZbt9y8acvNmzbeeGvtnu+uaPeZid0dd9ly86bJDZv33PnAjtu3brzx1sfv/X4f2yymmfv2D/eVdxT+HZIC6eFZoqfWaB0IQLyCyWMYPJekr1qn47iO40xKEpdhf9/fI4eSd113h0yzlt0xsJ+9hEi2tO0tMs8bw/sY4ZfqBNOssSWcpB5QphKoNZkM/MinyzZY/bxrs84J/Fq0jvk8fu/3t9y8Cct77nxAlntkz50P7LnzAW3l5IbNO27fKi8fubu60sN2Z+ONtxb+vZEhoQfrvL+Gv75z6eNVmR0PhWlmPaJt3GXSc5dm937GwVyR+le0zrigWmdfecfkhs1Y3vWtbSiAJjdslp63yQ2bsRJS2XPnAxtvvBWox8xaQcqdjTfeuuP2rZMbNm+88VbpfJNzoYhBk+TUWJA6bOONt5ZKpY033rrnzgcev/f70mCtbViz61vbtHMRw+jBOr8dt+dGF3GpzRoJ0b1G64wF6GHbc+cDSP1z3/5h/f4Dj9xdlWwuKtpx+1Ypa3bcvhVdW9laBwfUzrLl5k3YXgQgmz1yd1U8seXmTU9tewhvwVLPTz78/OTD9fsP1O75rthRji/K7Ni2LTdvwsqZid0sj0ylB+ukafo3YyUe190xuBvkDIAwTS/JT0XrmI9YR8RQv//A5IbNMxO7ZRukbDVxz0zsRrrv3To4oPrWlps3oViBM1A5YV6D2iP3yN1VKYbU9tQV63RsG46v7UIMozfrpGl6LU3fW90YDxkYJ9P0vTS9pv5OtI75SOJ+fvLhjTfeilpHJAFWZB1sqU2HkzVZ68B2Mo+u/tVOv13f2rbj9q2aimgdIvRsHcZoBK1jPh3HdfaVd0ivl6yc3LBZiqEuPWz1pXEa9IxhYzmadJ1JSaSeC2ZSm7Tl5k0YztlX3tHFOh3bRuuMA7SOYUHrmI86IF+//8CWmzdh3GXH7VvRqSW5HgP72og9hkzUI4Bd39qGCdmYPiDrsTHWywg/1uBfrUmP3F3FLpiDoG6PCgkrO7ZtcsNmWsd4aB3DgtYZd7LXja7oSlL016kg+6/xsL23lhgPrWNY0Dqkz7DmIP2F1jEsaB3SZ7J9cYSsBVrHsKB1CCFDDa1jWNA6hJChhtYxLGgdQshQQ+sYFrp1Tjz4WOH/kRFCiPDekdcKSY6MAYVunXOP/cX/vwFPZKNoFI2iUQRHV9ccGJDCcRTQCKDXOlfXHBjwRDaKRtEoGkVw9P7+8wEpHEcBjQB6rfP///8NCR0Dns5G0SgaRaNopnHaycnr6F8sjgKaAgDDS8T6utFu+wAAAABJRU5ErkJggg==

1、    Sigprocmask()屏蔽信号,防止在此过程中受到信号的干扰。
2、    设置当前VCPU状态为KVM_MP_STATE_UNINITIALIZED
3、    配置APICmmio相关信息
4、    VCPU中保存的上下文信息写入指定位置
5、    然后的工作交由__vcpu_run完成
6、    __vcpu_run最终调用vcpu_enter_guest,该函数实现了进入Guest,并执行Guest OS具体指令的操作。        
7、    vcpu_enter_guest最终调用kvm_x86_ops中的run函数运行。对应于Intel平台,该函数为vmx_vcpu_run(设置Guest CR3和其他寄存器、EPT/影子页表相关设置、汇编代码VMLAUNCH切换到非根模式,执行Guest目标代码)
8、    Guest代码执行到敏感指令或因其他原因(比如中断/异常)VM-Exit退出非根模式,返回到vcpu_enter_guest函数继续执行。
9、    vcpu_enter_guest函数中会判断VM-Exit原因,并进行相应处理。
10、处理完成后VM-EntryGuest重新执行Guest代码,或重新等待下次调度。

3、代码分析
kvm_vcpu_ioctl():




  • /*

  •   * kvm ioctl VCPU指令的入口,传入的fd为KVM_CREATE_VCPU中返回的fd。
  •   * 主要针对具体的VCPU进行参数设置。如:相关寄存器的读
  •   * 写、中断控制等
  •   */

  • static long kvm_vcpu_ioctl(struct file *filp,
  •                unsigned int ioctl, unsigned long arg)
  • {
  •     struct kvm_vcpu *vcpu = filp->private_data;
  •     void __user *argp = (void __user *)arg;
  •     int r;
  •     struct kvm_fpu *fpu = NULL;
  •     struct kvm_sregs *kvm_sregs = NULL;

  •     if (vcpu->kvm->mm != current->mm)
  •         return -EIO;

  • #if defined(CONFIG_S390) || defined(CONFIG_PPC) || defined(CONFIG_MIPS)
  •     /*
  •      * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
  •      * so vcpu_load() would break it.
  •      */
  •     if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT)
  •         return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
  • #endif

  •     // KVM虚拟机VCPU数据结构载入物理CPU
  •     r = vcpu_load(vcpu);
  •     if (r)
  •         return r;
  •     switch (ioctl) {
  •     /*
  •      * 运行虚拟机,最终通过执行VMLAUNCH指令进入non root模式,
  •      * 进入虚拟机运行。当虚拟机内部执行敏感指令时,由硬
  •      * 件触发VM-exit,返回到root模式
  •      */
  •     case KVM_RUN:
  •         r = -EINVAL;
  •         // 不能带参数。
  •         if (arg)
  •             goto out;
  •         // 运行VCPU(即运行虚拟机)的入口函数
  •         r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run);
  •         trace_kvm_userspace_exit(vcpu->run->exit_reason, r);
  •         break;
  • ...

kvm_vcpu_ioctl()-->kvm_arch_vcpu_ioctl_run()-->__vcpu_run():



  • static int __vcpu_run(struct kvm_vcpu *vcpu)

  • {
  •     int r;
  •     struct kvm *kvm = vcpu->kvm;

  •     vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
  •     /*设置vcpu->arch.apic->vapic_page*/
  •     r = vapic_enter(vcpu);
  •     if (r) {
  •         srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
  •         return r;
  •     }

  •     r = 1;
  •     while (r > 0) {
  •         /*检查状态*/
  •         if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
  •          !vcpu->arch.apf.halted)
  •          /* 进入Guest模式,最终通过VMLAUNCH指令实现*/
  •             r = vcpu_enter_guest(vcpu);
  •         else {/*什么情况下会走到这里?*/
  •             srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
  •             /*阻塞VCPU,其实就是schddule()调度出去,但在有特殊情况时(比如有挂起的定时器或信号时),不进行调度而直接退出*/
  •             kvm_vcpu_block(vcpu);
  •             vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
  •             if (kvm_check_request(KVM_REQ_UNHALT, vcpu)) {
  •                 kvm_apic_accept_events(vcpu);
  •                 switch(vcpu->arch.mp_state) {
  •                 case KVM_MP_STATE_HALTED:
  •                     vcpu->arch.pv.pv_unhalted = false;
  •                     vcpu->arch.mp_state =
  •                         KVM_MP_STATE_RUNNABLE;
  •                 case KVM_MP_STATE_RUNNABLE:
  •                     vcpu->arch.apf.halted = false;
  •                     break;
  •                 case KVM_MP_STATE_INIT_RECEIVED:
  •                     break;
  •                 default:
  •                     r = -EINTR;
  •                     break;
  •                 }
  •             }
  •         }

  •         if (r requests);
  •         if (kvm_cpu_has_pending_timer(vcpu))
  •             kvm_inject_pending_timer_irqs(vcpu);

  •         if (dm_request_for_irq_injection(vcpu)) {
  •             r = -EINTR;
  •             vcpu->run->exit_reason = KVM_EXIT_INTR;
  •             ++vcpu->stat.request_irq_exits;
  •         }

  •         kvm_check_async_pf_completion(vcpu);

  •         if (signal_pending(current)) {
  •             r = -EINTR;
  •             vcpu->run->exit_reason = KVM_EXIT_INTR;
  •             ++vcpu->stat.signal_exits;
  •         }
  •         /*这是kvm中的一个调度时机点,即选择新VCPU运行的时机点*/
  •         if (need_resched()) {
  •             srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
  •             kvm_resched(vcpu);
  •             vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
  •         }
  •     }

  •     srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);

  •     vapic_exit(vcpu);

  •     return r;
  • }
kvm_vcpu_ioctl()-->kvm_arch_vcpu_ioctl_run()-->__vcpu_run()-->vcpu_enter_guest():



  • /* 进入Guest模式,最终通过VMLAUNCH指令实现*/

  • static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
  • {
  •     int r;
  •     bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
  •         vcpu->run->request_interrupt_window;
  •     bool req_immediate_exit = false;
  •     /*进入Guest模式前先处理相关挂起的请求*/
  •     if (vcpu->requests) {
  •         /*卸载MMU*/
  •         if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu))
  •             kvm_mmu_unload(vcpu);
  •         /*定时器迁移*/
  •         if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
  •             __kvm_migrate_timers(vcpu);
  •         /*主时钟更新*/
  •         if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
  •             kvm_gen_update_masterclock(vcpu->kvm);
  •         /*全局时钟更新*/
  •         if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
  •             kvm_gen_kvmclock_update(vcpu);
  •         /*虚拟机时钟更新*/
  •         if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
  •             r = kvm_guest_time_update(vcpu);
  •             if (unlikely(r))
  •                 goto out;
  •         }
  •         /*更新mmu*/
  •         if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
  •             kvm_mmu_sync_roots(vcpu);
  •         /*刷新TLB*/
  •         if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
  •             kvm_x86_ops->tlb_flush(vcpu);
  •         if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
  •             vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
  •             r = 0;
  •             goto out;
  •         }
  •         if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
  •             vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
  •             r = 0;
  •             goto out;
  •         }
  •         if (kvm_check_request(KVM_REQ_DEACTIVATE_FPU, vcpu)) {
  •             vcpu->fpu_active = 0;
  •             kvm_x86_ops->fpu_deactivate(vcpu);
  •         }
  •         if (kvm_check_request(KVM_REQ_APF_HALT, vcpu)) {
  •             /* Page is swapped out. Do synthetic halt */
  •             vcpu->arch.apf.halted = true;
  •             r = 1;
  •             goto out;
  •         }
  •         if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
  •             record_steal_time(vcpu);
  •         if (kvm_check_request(KVM_REQ_NMI, vcpu))
  •             process_nmi(vcpu);
  •         if (kvm_check_request(KVM_REQ_PMU, vcpu))
  •             kvm_handle_pmu_event(vcpu);
  •         if (kvm_check_request(KVM_REQ_PMI, vcpu))
  •             kvm_deliver_pmi(vcpu);
  •         if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
  •             vcpu_scan_ioapic(vcpu);
  •     }
  •     // 检查是否有事件请求
  •     if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
  •         kvm_apic_accept_events(vcpu);
  •         if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
  •             r = 1;
  •             goto out;
  •         }
  •         // 注入阻塞的事件,中断,异常和nmi等
  •         inject_pending_event(vcpu);

  •         /* enable NMI/IRQ window open exits if needed */
  •         /*
  •          * 使能NMI/IRQ window,参见Intel64 System Programming Guide 25.3节
  •          * 当使能了interrupt-window exiting或NMI-window exiting(由VMCS中相关字段控制)
  •          * 表示在刚进入虚拟机后,就会立刻因为有pending或注入的中断导致VM-exit
  •          */
  •         if (vcpu->arch.nmi_pending)
  •             req_immediate_exit =
  •                 kvm_x86_ops->enable_nmi_window(vcpu) != 0;
  •         else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
  •             req_immediate_exit =
  •                 kvm_x86_ops->enable_irq_window(vcpu) != 0;

  •         if (kvm_lapic_enabled(vcpu)) {
  •             /*
  •              * Update architecture specific hints for APIC
  •              * virtual interrupt delivery.
  •              */
  •             if (kvm_x86_ops->hwapic_irr_update)
  •                 kvm_x86_ops->hwapic_irr_update(vcpu,
  •                     kvm_lapic_find_highest_irr(vcpu));
  •             update_cr8_intercept(vcpu);
  •             kvm_lapic_sync_to_vapic(vcpu);
  •         }
  •     }
  •     // 装载MMU,待深入分析
  •     r = kvm_mmu_reload(vcpu);
  •     if (unlikely(r)) {
  •         goto cancel_injection;
  •     }

  •     preempt_disable();
  •     // 进入Guest前期准备,架构相关
  •     kvm_x86_ops->prepare_guest_switch(vcpu);
  •     if (vcpu->fpu_active)
  •         kvm_load_guest_fpu(vcpu);
  •     kvm_load_guest_xcr0(vcpu);

  •     vcpu->mode = IN_GUEST_MODE;

  •     /* We should set ->mode before check ->requests,
  •      * see the comment in make_all_cpus_request.
  •      */
  •     smp_mb();

  •     local_irq_disable();
  •     /*
  •      * 如果VCPU处于EXITING_GUEST_MODE或者vcpu->requests(?)或者需要调度或者
  •      * 有挂起的信号,则放弃
  •      */
  •     if (vcpu->mode == EXITING_GUEST_MODE || vcpu->requests
  •      || need_resched() || signal_pending(current)) {
  •         vcpu->mode = OUTSIDE_GUEST_MODE;
  •         smp_wmb();
  •         local_irq_enable();
  •         preempt_enable();
  •         r = 1;
  •         goto cancel_injection;
  •     }

  •     srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
  •     // req_immediate_exit在前面使能NMI/IRQ window失败时设置,此时需要立即退出,触发重新调度
  •     if (req_immediate_exit)
  •         smp_send_reschedule(vcpu->cpu);
  •     // 计算虚拟机的enter时间
  •     kvm_guest_enter();
  •     // 调试相关
  •     if (unlikely(vcpu->arch.switch_db_regs)) {
  •         set_debugreg(0, 7);
  •         set_debugreg(vcpu->arch.eff_db[0], 0);
  •         set_debugreg(vcpu->arch.eff_db[1], 1);
  •         set_debugreg(vcpu->arch.eff_db[2], 2);
  •         set_debugreg(vcpu->arch.eff_db[3], 3);
  •     }

  •     trace_kvm_entry(vcpu->vcpu_id);
  •     // 调用架构相关的run接口(vmx_vcpu_run),进入Guest模式
  •     kvm_x86_ops->run(vcpu);

  •    
  •     // 此处开始,说明已经发生了VM-exit,退出了Guest模式
  •     /*
  •      * If the guest has used debug registers, at least dr7
  •      * will be disabled while returning to the host.
  •      * If we don't have active breakpoints in the host, we don't
  •      * care about the messed up debug address registers. But if
  •      * we have some of them active, restore the old state.
  •      */
  •     if (hw_breakpoint_active())
  •         hw_breakpoint_restore();
  •     /*记录Guest退出前的TSC时钟*/
  •     vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu,
  •                                native_read_tsc());
  •     // 设置模式
  •     vcpu->mode = OUTSIDE_GUEST_MODE;
  •     smp_wmb();

  •     /* Interrupt is enabled by handle_external_intr() */
  •     kvm_x86_ops->handle_external_intr(vcpu);

  •     ++vcpu->stat.exits;

  •     /*
  •      * We must have an instruction between local_irq_enable() and
  •      * kvm_guest_exit(), so the timer interrupt isn't delayed by
  •      * the interrupt shadow. The stat.exits increment will do nicely.
  •      * But we need to prevent reordering, hence this barrier():
  •      */
  •     barrier();
  •     // 计算虚拟机的退出时间,其中还开中断了?
  •     kvm_guest_exit();
  •    
  •     preempt_enable();

  •     vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);

  •     /*
  •      * Profile KVM exit RIPs:
  •      */
  •     // Profile(采样计数,用于性能分析和调优)相关
  •     if (unlikely(prof_on == KVM_PROFILING)) {
  •         unsigned long rip = kvm_rip_read(vcpu);
  •         profile_hit(KVM_PROFILING, (void *)rip);
  •     }

  •     if (unlikely(vcpu->arch.tsc_always_catchup))
  •         kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);

  •     if (vcpu->arch.apic_attention)
  •         kvm_lapic_sync_from_vapic(vcpu);
  •     /*
  •      * 调用vmx_handle_exit()处理虚拟机异常,异常原因及其它关键信息
  •      * 已经在之前获取。
  •      */
  •     r = kvm_x86_ops->handle_exit(vcpu);
  •     return r;

  • cancel_injection:
  •     kvm_x86_ops->cancel_injection(vcpu);
  •     if (unlikely(vcpu->arch.apic_attention))
  •         kvm_lapic_sync_from_vapic(vcpu);
  • out:
  •     return r;
  • }

kvm_vcpu_ioctl()-->kvm_arch_vcpu_ioctl_run()-->__vcpu_run()-->vcpu_enter_guest()-->vmx_vcpu_run():


/*
  * 运行虚拟机,进入Guest模式,即non root模式
  */
static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
    struct vcpu_vmx *vmx = to_vmx(vcpu);
    unsigned long debugctlmsr;

    /* Record the guest's net vcpu time for enforced NMI injections. */
    // nmi注入?跟nmi_watchdog相关?
    if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
        vmx->entry_time = ktime_get();

    /* Don't enter VMX if guest state is invalid, let the exit handler
       start emulation until we arrive back to a valid state */
    if (vmx->emulation_required)
        return;

    if (vmx->nested.sync_shadow_vmcs) {
        copy_vmcs12_to_shadow(vmx);
        vmx->nested.sync_shadow_vmcs = false;
    }
    // 写入Guest的RSP寄存器信息至VMCS相关位置中
    if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
        vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
    // 写入Guest的RIP寄存器信息至VMCS相关位置中
    if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty))
        vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);

    /* When single-stepping over STI and MOV SS, we must clear the
     * corresponding interruptibility bits in the guest state. Otherwise
     * vmentry fails as it then expects bit 14 (BS) in pending debug
     * exceptions being set, but that's not correct for the guest debugging
     * case. */
    // 单步调试时,需要禁用Guest中断
    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
        vmx_set_interrupt_shadow(vcpu, 0);

    atomic_switch_perf_msrs(vmx);
    debugctlmsr = get_debugctlmsr();
    // vmx->__launched用于判断当前VCPU是否已经VMLAUNCH了
    vmx->__launched = vmx->loaded_vmcs->launched;
    // 执行VMLAUNCH指令进入Guest模式,虚拟机开始运行
    asm(
        /* Store host registers */
        /*将相关寄存器压栈*/
        "push %%" _ASM_DX "; push %%" _ASM_BP ";"/*BP压栈*/
        /*为guest的rcx寄存器保留个位置,所以这里压两次栈*/
        "push %%" _ASM_CX " \n\t" /* placeholder for guest rcx */
        "push %%" _ASM_CX " \n\t"
        /*
         * %c表示用来表示使用立即数替换,但不使用立即数的语法,at&t汇编中表示立即数的语法前面有一个$,而用了%c后,就去掉了这个$。
         * 主要是用在间接寻址的情况,这种情况下如果直接使用$立即数的方式的话,会报语法错误。
         * [host_rsp]是后面输入部分定义的tag,使用%tag方式可以直接引用,%0是后面输入输出部分中的第一个操作数,即vmx,这里是间接寻址
         * %c[host_rsp](%0)整体来看就是vmx(以寄存器ecx传入)中的host_rsp成员。
         * 所以,如下语句的整体含义就是比较当前SP寄存器和vmx->host_rsp的值。
         */
        /*如果当前RSP和vmx->rsp相等,那就不用mov了,否则将当前RSP保存到vmx中*/
        "cmp %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
        "je 1f \n\t"
        "mov %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
        /*执行ASM_VMX_VMWRITE_RSP_RDX指令,当出现异常时直接重启,由__ex()实现*/
        __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
        "1: \n\t"
        /* Reload cr2 if changed */
        /*比较当前CR2寄存器和vmx中保存的CR2寄存器内容,如果不相等,就从vmx中重新CR2内容到当前CR2寄存器中*/
        "mov %c[cr2](%0), %%" _ASM_AX " \n\t"
        "mov %%cr2, %%" _ASM_DX " \n\t"
        "cmp %%" _ASM_AX ", %%" _ASM_DX " \n\t"
        "je 2f \n\t"
        "mov %%" _ASM_AX", %%cr2 \n\t"
        "2: \n\t"
        /* Check if vmlaunch of vmresume is needed */
        /*判断vcpu_vmx->__launched,确认是否需要执行VMLAUNCH*/
        "cmpl $0, %c[launched](%0) \n\t"
        /* Load guest registers. Don't clobber flags. */
        /*加载guest寄存器,其实就是从vmx中加载*/
        "mov %c[rax](%0), %%" _ASM_AX " \n\t"
        "mov %c[rbx](%0), %%" _ASM_BX " \n\t"
        "mov %c[rdx](%0), %%" _ASM_DX " \n\t"
        "mov %c[rsi](%0), %%" _ASM_SI " \n\t"
        "mov %c[rdi](%0), %%" _ASM_DI " \n\t"
        "mov %c[rbp](%0), %%" _ASM_BP " \n\t"
#ifdef CONFIG_X86_64
        "mov %c[r8](%0),  %%r8  \n\t"
        "mov %c[r9](%0),  %%r9  \n\t"
        "mov %c[r10](%0), %%r10 \n\t"
        "mov %c[r11](%0), %%r11 \n\t"
        "mov %c[r12](%0), %%r12 \n\t"
        "mov %c[r13](%0), %%r13 \n\t"
        "mov %c[r14](%0), %%r14 \n\t"
        "mov %c[r15](%0), %%r15 \n\t"
#endif
        "mov %c[rcx](%0), %%" _ASM_CX " \n\t" /* kills %0 (ecx) */

        /* Enter guest mode */
        "jne 1f \n\t"
        /* 执行VMLAUNCH指令,进入Guest模式*/
        __ex(ASM_VMX_VMLAUNCH) "\n\t"
        "jmp 2f \n\t"
        /* 执行VMRESUME指令,从Guest模式恢复到root模式*/
        "1: " __ex(ASM_VMX_VMRESUME) "\n\t"
        "2: "
        /* Save guest registers, load host registers, keep flags */
        "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
        "pop %0 \n\t"
        "mov %%" _ASM_AX ", %c[rax](%0) \n\t"
        "mov %%" _ASM_BX ", %c[rbx](%0) \n\t"
        __ASM_SIZE(pop) " %c[rcx](%0) \n\t"
        "mov %%" _ASM_DX ", %c[rdx](%0) \n\t"
        "mov %%" _ASM_SI ", %c[rsi](%0) \n\t"
        "mov %%" _ASM_DI ", %c[rdi](%0) \n\t"
        "mov %%" _ASM_BP ", %c[rbp](%0) \n\t"
#ifdef CONFIG_X86_64
        "mov %%r8,  %c[r8](%0) \n\t"
        "mov %%r9,  %c[r9](%0) \n\t"
        "mov %%r10, %c[r10](%0) \n\t"
        "mov %%r11, %c[r11](%0) \n\t"
        "mov %%r12, %c[r12](%0) \n\t"
        "mov %%r13, %c[r13](%0) \n\t"
        "mov %%r14, %c[r14](%0) \n\t"
        "mov %%r15, %c[r15](%0) \n\t"
#endif
        "mov %%cr2, %%" _ASM_AX "   \n\t"
        "mov %%" _ASM_AX ", %c[cr2](%0) \n\t"

        "pop  %%" _ASM_BP "; pop  %%" _ASM_DX " \n\t"
        "setbe %c[fail](%0) \n\t"
        ".pushsection .rodata \n\t"
        ".global vmx_return \n\t"
        "vmx_return: " _ASM_PTR " 2b \n\t"
        ".popsection"
     : : "c"(vmx), "d"((unsigned long)HOST_RSP),
        [launched]"i"(offsetof(struct vcpu_vmx, __launched)),
        [fail]"i"(offsetof(struct vcpu_vmx, fail)),
        /*[host_rsp]是tag,可以在前面以%[host_rsp]方式引用*/
        [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)),
        [rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])),
        [rbx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBX])),
        [rcx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RCX])),
        [rdx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDX])),
        [rsi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RSI])),
        [rdi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDI])),
        [rbp]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBP])),
#ifdef CONFIG_X86_64
        [r8]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R8])),
        [r9]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R9])),
        [r10]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R10])),
        [r11]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R11])),
        [r12]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R12])),
        [r13]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R13])),
        [r14]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R14])),
        [r15]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R15])),
#endif
        [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)),
        [wordsize]"i"(sizeof(ulong))
     : "cc", "memory"/*clobber list,cc表示寄存器,memory表示内存*/
#ifdef CONFIG_X86_64
        , "rax", "rbx", "rdi", "rsi"
        , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
#else
        , "eax", "ebx", "edi", "esi"
#endif
     );
    // 运行到这里,说明已经发生了VM-exit,返回到了root模式
    /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
    if (debugctlmsr)
        update_debugctlmsr(debugctlmsr);

#ifndef CONFIG_X86_64
    /*
     * The sysexit path does not restore ds/es, so we must set them to
     * a reasonable value ourselves.
     *
     * We can't defer this to vmx_load_host_state() since that function
     * may be executed in interrupt context, which saves and restore segments
     * around it, nullifying its effect.
     */
    /*重新加载ds/es段寄存器,因为VM-exit不会自动加载他们*/
    loadsegment(ds, __USER_DS);
    loadsegment(es, __USER_DS);
#endif

    vcpu->arch.regs_avail = ~((1

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-155820-1-1.html 上篇帖子: KVM源代码分析3:CPU虚拟化 下篇帖子: KVM(系统虚拟化模块)安装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表