اندروید یک پیاده سازی مرجع از تمام اجزای مورد نیاز برای پیاده سازی چارچوب مجازی سازی اندروید ارائه می کند. در حال حاضر این پیاده سازی به ARM64 محدود شده است. این صفحه معماری چارچوب را توضیح می دهد.
پس زمینه
معماری Arm اجازه میدهد تا چهار سطح استثنایی، با سطح استثنا 0 (EL0) کمترین امتیاز و سطح استثنا 3 (EL3) بیشترین امتیاز را داشته باشد. بزرگترین بخش از پایگاه کد اندروید (همه اجزای فضای کاربری) در EL0 اجرا می شود. بقیه چیزی که معمولا "اندروید" نامیده می شود، هسته لینوکس است که در EL1 اجرا می شود.
لایه EL2 امکان معرفی یک هایپروایزر را فراهم می کند که با تضمین محرمانه بودن و یکپارچگی قوی، حافظه و دستگاه ها را در pVM های جداگانه در EL1/EL0 ایزوله می کند.
هایپروایزر
ماشین مجازی مبتنی بر هسته محافظت شده (pKVM) بر اساس هایپروایزر لینوکس KVM ساخته شده است، که با توانایی محدود کردن دسترسی به بارهای در حال اجرا در ماشین های مجازی مهمان با علامت "محافظت" در زمان ایجاد توسعه یافته است.
KVM/arm64 بسته به در دسترس بودن برخی ویژگیهای CPU، یعنی Virtualization Host Extensions (VHE) (ARMv8.1 و جدیدتر) از حالتهای اجرای مختلف پشتیبانی میکند. در یکی از این حالتها، که معمولاً به عنوان حالت غیر VHE شناخته میشود، کد هایپروایزر هنگام بوت از تصویر هسته جدا میشود و در EL2 نصب میشود، در حالی که خود هسته در EL1 اجرا میشود. اگرچه بخشی از پایگاه کد لینوکس است، مؤلفه EL2 KVM یک مؤلفه کوچک است که وظیفه سوئیچ بین چندین EL1 را بر عهده دارد. جزء Hypervisor با لینوکس کامپایل شده است، اما در یک بخش حافظه اختصاصی جداگانه از تصویر vmlinux
قرار دارد. pKVM از این طراحی با گسترش کد هایپروایزر با ویژگیهای جدید استفاده میکند که به آن اجازه میدهد محدودیتهایی بر هسته میزبان اندروید و فضای کاربر اعمال کند و دسترسی میزبان به حافظه مهمان و هایپروایزر را محدود کند.
ماژول های فروشنده pKVM
یک ماژول فروشنده pKVM یک ماژول مخصوص سخت افزار است که دارای عملکردهای خاص دستگاه است، مانند درایورهای واحد مدیریت حافظه ورودی-خروجی (IOMMU). این ماژولها به شما امکان میدهند ویژگیهای امنیتی را که نیاز به دسترسی سطح استثنا 2 (EL2) به pKVM دارند، پورت کنید.
برای یادگیری نحوه پیاده سازی و بارگذاری یک ماژول فروشنده pKVM، به پیاده سازی ماژول فروشنده pKVM مراجعه کنید.
رویه بوت
شکل زیر فرآیند بوت pKVM را نشان می دهد:
- بوت لودر در EL2 وارد هسته عمومی می شود.
- هسته عمومی تشخیص می دهد که در EL2 در حال اجرا است و خود را به EL1 محروم می کند در حالی که pKVM و ماژول های آن همچنان در EL2 کار می کنند. علاوه بر این، ماژولهای فروشنده pKVM در این زمان بارگیری میشوند.
- هسته عمومی به طور معمول بوت می شود و تمام درایورهای دستگاه لازم را تا رسیدن به فضای کاربر بارگیری می کند. در این مرحله، pKVM در جای خود قرار دارد و جداول صفحه مرحله 2 را مدیریت می کند.
رویه بوت به بوت لودر اعتماد می کند که یکپارچگی تصویر هسته را فقط در طول راه اندازی اولیه حفظ کند. هنگامی که هسته محروم می شود، دیگر توسط هایپروایزر قابل اعتماد تلقی نمی شود، که پس از آن مسئول محافظت از خود حتی اگر هسته در معرض خطر قرار گرفته باشد.
وجود هسته اندروید و هایپروایزر در یک تصویر باینری یک رابط ارتباطی بسیار محکم بین آنها ایجاد می کند. این اتصال محکم به روز رسانی اتمی دو جزء را تضمین می کند، که از نیاز به پایدار نگه داشتن رابط بین آنها جلوگیری می کند و انعطاف پذیری زیادی را بدون به خطر انداختن قابلیت نگهداری طولانی مدت ارائه می دهد. کوپلینگ محکم همچنین زمانی که هر دو مؤلفه می توانند بدون تأثیر بر تضمین های امنیتی ارائه شده توسط هایپروایزر با یکدیگر همکاری کنند، امکان بهینه سازی عملکرد را فراهم می کند.
علاوه بر این، پذیرش GKI در اکوسیستم اندروید به طور خودکار به هایپروایزر pKVM اجازه می دهد تا در دستگاه های اندرویدی به صورت باینری مشابه هسته مستقر شود.
حفاظت از دسترسی به حافظه CPU
معماری Arm یک واحد مدیریت حافظه (MMU) را به دو مرحله مستقل تقسیم میکند، که هر دو میتوانند برای پیادهسازی ترجمه آدرس و کنترل دسترسی به بخشهای مختلف حافظه استفاده شوند. مرحله 1 MMU توسط EL1 کنترل می شود و سطح اول ترجمه آدرس را امکان پذیر می کند. مرحله 1 MMU توسط لینوکس برای مدیریت فضای آدرس مجازی ارائه شده به هر فرآیند فضای کاربر و فضای آدرس مجازی خود استفاده می شود.
مرحله 2 MMU توسط EL2 کنترل می شود و استفاده از ترجمه آدرس دوم را در آدرس خروجی MMU مرحله 1 امکان پذیر می کند که منجر به یک آدرس فیزیکی (PA) می شود. ترجمه مرحله 2 می تواند توسط هایپروایزرها برای کنترل و ترجمه دسترسی های حافظه از تمام ماشین های مجازی مهمان استفاده شود. همانطور که در شکل 2 نشان داده شده است، زمانی که هر دو مرحله ترجمه فعال هستند، آدرس خروجی مرحله 1 یک آدرس فیزیکی متوسط (IPA) نامیده می شود. توجه: آدرس مجازی (VA) به یک IPA و سپس به یک PA ترجمه می شود.
از لحاظ تاریخی، KVM با فعال کردن ترجمه مرحله 2 در حین اجرای مهمان ها و با غیرفعال شدن مرحله 2 هنگام اجرای هسته لینوکس میزبان اجرا می شود. این معماری به دسترسیهای حافظه از MMU مرحله 1 میزبان اجازه میدهد تا از MMU مرحله 2 عبور کند، بنابراین دسترسی نامحدود از میزبان به صفحات حافظه مهمان را امکانپذیر میسازد. از طرف دیگر، pKVM حفاظت مرحله 2 را حتی در زمینه میزبان فعال می کند و هایپروایزر را به جای میزبان، مسئول محافظت از صفحات حافظه مهمان می کند.
KVM به طور کامل از ترجمه آدرس در مرحله 2 برای پیاده سازی نگاشت های پیچیده IPA/PA برای مهمانان استفاده می کند، که با وجود تکه تکه شدن فیزیکی، توهم حافظه پیوسته را برای مهمانان ایجاد می کند. با این حال، استفاده از مرحله 2 MMU برای میزبان فقط به کنترل دسترسی محدود شده است. مرحله میزبان 2 با هویت نگاشت شده است و اطمینان حاصل می کند که حافظه پیوسته در فضای میزبان IPA در فضای PA به هم پیوسته است. این معماری امکان استفاده از نگاشتهای بزرگ را در جدول صفحه فراهم میکند و در نتیجه فشار بر بافر نگاهی ترجمه (TLB) را کاهش میدهد. از آنجا که نگاشت هویت می تواند توسط PA نمایه شود، مرحله میزبان 2 نیز برای ردیابی مالکیت صفحه به طور مستقیم در جدول صفحه استفاده می شود.
حفاظت از دسترسی مستقیم به حافظه (DMA).
همانطور که قبلاً توضیح داده شد، برداشتن نقشه صفحات مهمان از میزبان لینوکس در جداول صفحه CPU یک مرحله ضروری اما ناکافی برای محافظت از حافظه مهمان است. pKVM همچنین نیاز به محافظت در برابر دسترسیهای حافظه ایجاد شده توسط دستگاههای دارای DMA تحت کنترل هسته میزبان و احتمال حمله DMA توسط یک میزبان مخرب دارد. برای جلوگیری از دسترسی چنین دستگاهی به حافظه مهمان، pKVM به سخت افزار واحد مدیریت حافظه ورودی-خروجی (IOMMU) برای هر دستگاه دارای DMA در سیستم، همانطور که در شکل 3 نشان داده شده است، نیاز دارد.
حداقل، سختافزار IOMMU ابزاری را برای اعطا و لغو دسترسی خواندن/نوشتن برای دستگاه به حافظه فیزیکی با جزئیات صفحه فراهم میکند. با این حال، این سختافزار IOMMU استفاده از دستگاهها را در pVM محدود میکند، زیرا آنها مرحله 2 نقشهبرداری هویتی را فرض میکنند.
برای اطمینان از جداسازی بین ماشین های مجازی، تراکنش های حافظه ایجاد شده از طرف نهادهای مختلف باید توسط IOMMU قابل تشخیص باشند تا بتوان از مجموعه مناسب جداول صفحه برای ترجمه استفاده کرد.
علاوه بر این، کاهش مقدار کد اختصاصی SoC در EL2 یک استراتژی کلیدی برای کاهش پایه محاسباتی قابل اعتماد کلی (TCB) pKVM است و برخلاف گنجاندن درایورهای IOMMU در هایپروایزر است. برای کاهش این مشکل، میزبان در EL1 مسئول وظایف مدیریت کمکی IOMMU، مانند مدیریت توان، مقداردهی اولیه و در صورت لزوم، مدیریت وقفه است.
با این حال، قرار دادن میزبان در کنترل وضعیت دستگاه، الزامات بیشتری را در رابط برنامهنویسی سختافزار IOMMU ایجاد میکند تا اطمینان حاصل شود که بررسیهای مجوز را نمیتوان با روشهای دیگری دور زد، به عنوان مثال، پس از بازنشانی دستگاه.
یک IOMMU استاندارد و به خوبی پشتیبانی شده برای دستگاههای بازویی که هم جداسازی و هم انتساب مستقیم را ممکن میسازد، معماری واحد مدیریت حافظه سیستم بازو (SMMU) است. این معماری راه حل مرجع توصیه شده است.
مالکیت حافظه
در زمان راهاندازی، فرض میشود که تمام حافظه غیرهایپروایزر متعلق به میزبان است و به همین ترتیب توسط هایپروایزر ردیابی میشود. هنگامی که یک pVM ایجاد میشود، میزبان صفحات حافظه را اهدا میکند تا به آن اجازه راهاندازی داده شود و هایپروایزر مالکیت آن صفحات را از میزبان به pVM منتقل میکند. بنابراین، هایپروایزر محدودیتهای کنترل دسترسی را در جدول صفحه مرحله 2 میزبان اعمال میکند تا از دسترسی مجدد به صفحات جلوگیری کند و محرمانه بودن را برای مهمان فراهم کند.
ارتباط بین میزبان و مهمانان با به اشتراک گذاری حافظه کنترل شده بین آنها امکان پذیر می شود. مهمانان مجاز هستند برخی از صفحات خود را با استفاده از فراخوانی با میزبان به اشتراک بگذارند، که به هایپروایزر دستور می دهد تا آن صفحات را در جدول صفحه میزبان مرحله 2 مجدداً نقشه برداری کند. به طور مشابه، ارتباط میزبان با TrustZone با عملیات اشتراک گذاری حافظه و/یا امانت امکان پذیر می شود، که همه آنها به دقت توسط pKVM با استفاده از مشخصات فریمور فریمورک برای بازو (FF-A) نظارت و کنترل می شوند.
از آنجایی که نیازهای حافظه یک pVM می تواند در طول زمان تغییر کند، یک فراخوانی ارائه می شود که اجازه می دهد مالکیت صفحات مشخص شده متعلق به تماس گیرنده به میزبان واگذار شود. در عمل از این فراخوانی با پروتکل بالون virtio استفاده میشود تا به VMM اجازه میدهد تا حافظه را از pVM بازگرداند و pVM به صورت کنترلشده، VMM را از صفحات رها شده مطلع کند.
هایپروایزر مسئول ردیابی مالکیت تمام صفحات حافظه در سیستم و اینکه آیا آنها به اشتراک گذاشته می شوند یا به نهادهای دیگر قرض داده می شوند، است. بیشتر این ردیابی وضعیت با استفاده از ابرداده های پیوست شده به جداول صفحه میزبان و مهمانان مرحله 2، با استفاده از بیت های رزرو شده در ورودی های جدول صفحه (PTEs) انجام می شود که همانطور که از نام آنها پیداست، برای استفاده نرم افزاری رزرو شده اند.
میزبان باید اطمینان حاصل کند که سعی نمی کند به صفحاتی که توسط هایپروایزر غیرقابل دسترس شده اند دسترسی پیدا کند. یک دسترسی غیرقانونی میزبان باعث میشود که یک استثنا همزمان توسط هایپروایزر به میزبان تزریق شود، که میتواند منجر به دریافت سیگنال SEGV توسط وظیفه فضای کاربر مسئول شود یا هسته میزبان خراب شود. برای جلوگیری از دسترسیهای تصادفی، صفحات اهدایی به مهمانان برای تعویض یا ادغام توسط هسته میزبان فاقد شرایط هستند.
مدیریت وقفه و تایمر
وقفه ها بخش مهمی از نحوه تعامل مهمان با دستگاه ها و ارتباط بین CPU ها هستند، جایی که وقفه های بین پردازنده (IPI) مکانیسم اصلی ارتباط هستند. مدل KVM این است که تمام مدیریت وقفه مجازی را به میزبان در EL1 واگذار می کند، که برای این منظور به عنوان بخشی نامعتبر از هایپروایزر رفتار می کند.
pKVM یک شبیه سازی کامل Generic Interrupt Controller نسخه 3 (GICv3) را بر اساس کد KVM موجود ارائه می دهد. تایمر و IPIها به عنوان بخشی از این کد شبیه سازی نامعتبر مدیریت می شوند.
پشتیبانی از GICv3
رابط بین EL1 و EL2 باید اطمینان حاصل کند که حالت وقفه کامل برای میزبان EL1 قابل مشاهده است، از جمله کپی هایی از ثبات هایپروایزر مربوط به وقفه ها. این دید معمولاً با استفاده از مناطق حافظه مشترک، یکی در هر CPU مجازی (vCPU) انجام می شود.
کد پشتیبانی زمان اجرا رجیستر سیستم را می توان برای پشتیبانی از ثبت وقفه ایجاد شده نرم افزار (SGIR) و غیرفعال کردن ثبت وقفه (DIR) ساده سازی کرد. معماری الزام می کند که این ثبات ها همیشه در EL2 به دام بیفتند، در حالی که تله های دیگر تاکنون فقط برای کاهش خطا مفید بوده اند. همه چیز دیگر در سخت افزار انجام می شود.
در سمت MMIO، همه چیز در EL1 شبیهسازی میشود و از تمام زیرساختهای فعلی در KVM استفاده مجدد میشود. در نهایت، Wait for Interrupt (WFI) همیشه به EL1 رله میشود، زیرا این یکی از اصول اولیه زمانبندی است که KVM از آن استفاده میکند.
پشتیبانی از تایمر
مقدار مقایسه کننده برای تایمر مجازی باید در هر WFI به دام افتاده در معرض EL1 قرار گیرد تا EL1 بتواند وقفه های تایمر را در زمانی که vCPU مسدود است تزریق کند. تایمر فیزیکی کاملا شبیه سازی شده است و همه تله ها به EL1 رله می شوند.
هندلینگ MMIO
برای برقراری ارتباط با مانیتور ماشین مجازی (VMM) و انجام شبیهسازی GIC، تلههای MMIO باید برای تریاژ بیشتر به میزبان در EL1 بازگردانده شوند. pKVM به موارد زیر نیاز دارد:
- IPA و اندازه دسترسی
- داده ها در صورت نوشتن
- اندانی بودن CPU در نقطه به دام انداختن
علاوه بر این، تلههایی با یک ثبت نام عمومی (GPR) به عنوان منبع/مقصد با استفاده از یک شبه ثبت انتقال انتزاعی رله میشوند.
رابط های مهمان
یک مهمان می تواند با استفاده از ترکیبی از فراخوانی و دسترسی حافظه به مناطق به دام افتاده با مهمان محافظت شده ارتباط برقرار کند. فراخوانی بر اساس استاندارد SMCCC ، با یک محدوده برای تخصیص فروشنده توسط KVM در معرض نمایش قرار می گیرد. فراخوان های زیر برای مهمانان pKVM اهمیت ویژه ای دارند.
فراخوان های عمومی
- PSCI مکانیزم استانداردی را برای مهمان فراهم می کند تا چرخه حیات vCPU های خود را از جمله آنلاین شدن، آفلاین کردن و خاموش شدن سیستم کنترل کند.
- TRNG مکانیزم استانداردی را برای مهمان فراهم می کند تا از pKVM درخواست آنتروپی کند که تماس را به EL3 رله می کند. این مکانیسم به ویژه در مواردی مفید است که میزبان برای مجازی سازی یک مولد اعداد تصادفی سخت افزاری (RNG) قابل اعتماد نباشد.
فراخوانی pKVM
- اشتراک گذاری حافظه با میزبان تمام حافظه مهمان در ابتدا برای میزبان غیرقابل دسترسی است، اما دسترسی میزبان برای ارتباط با حافظه مشترک و برای دستگاههای مجازیسازی شده که به بافرهای مشترک متکی هستند، ضروری است. فراخوانی برای اشتراکگذاری و لغو اشتراکگذاری صفحات با میزبان به مهمان این امکان را میدهد تا بدون نیاز به دست دادن دقیقاً تصمیم بگیرد که چه بخشهایی از حافظه برای بقیه اندروید قابل دسترسی است.
- واگذاری حافظه به میزبان. تمام حافظه مهمان معمولاً تا زمانی که از بین نرود متعلق به مهمان است. این حالت می تواند برای ماشین های مجازی با عمر طولانی با نیازهای حافظه که در طول زمان متفاوت است، ناکافی باشد.
relinquish
فراخوانی به مهمان اجازه می دهد تا صریحاً مالکیت صفحات را بدون نیاز به خاتمه مهمان به میزبان بازگرداند. - به دام انداختن دسترسی به حافظه برای میزبان. به طور سنتی، اگر یک مهمان KVM به آدرسی دسترسی پیدا کند که با یک منطقه حافظه معتبر مطابقت ندارد، رشته vCPU به میزبان خارج می شود و دسترسی معمولاً برای MMIO استفاده می شود و توسط VMM در فضای کاربر شبیه سازی می شود. برای تسهیل این کار، pKVM باید جزئیات دستورالعمل خطا مانند آدرس، پارامترهای ثبت و احتمالاً محتویات آنها را به میزبان بازگرداند، که اگر تله پیش بینی نشده باشد، می تواند ناخواسته داده های حساس یک مهمان محافظت شده را در معرض دید قرار دهد. pKVM این مشکل را با تلقی کردن این خطاها بهعنوان کشنده حل میکند، مگر اینکه مهمان قبلاً یک فراخوانی برای شناسایی محدوده IPA معیوب به عنوان محدودهای که دسترسیها مجاز است به میزبان بازگردانده شود، صادر کرده باشد. این راه حل به عنوان محافظ MMIO شناخته می شود.
دستگاه ورودی/خروجی مجازی (virtio)
Virtio یک استاندارد محبوب، قابل حمل و بالغ برای پیاده سازی و تعامل با دستگاه های paravirtualized است. اکثر دستگاه هایی که در معرض مهمانان محافظت شده قرار می گیرند با استفاده از virtio اجرا می شوند. Virtio همچنین زیربنای اجرای vsock است که برای ارتباط بین مهمان محافظت شده و بقیه اندروید استفاده می شود.
دستگاههای Virtio معمولاً در فضای کاربر میزبان توسط VMM پیادهسازی میشوند، که دسترسیهای حافظه به دام افتاده را از مهمان به رابط MMIO دستگاه virtio رهگیری میکند و رفتار مورد انتظار را شبیهسازی میکند. دسترسی MMIO نسبتاً گران است زیرا هر دسترسی به دستگاه نیاز به یک رفت و برگشت به VMM و برگشت دارد، بنابراین بیشتر انتقال داده واقعی بین دستگاه و مهمان با استفاده از مجموعهای از صفات در حافظه انجام میشود. یک فرض کلیدی virtio این است که میزبان می تواند خودسرانه به حافظه مهمان دسترسی داشته باشد. این فرض در طراحی virtqueue مشهود است، که ممکن است حاوی نشانگرهایی به بافرهایی در مهمان باشد که شبیه سازی دستگاه برای دسترسی مستقیم به آنها در نظر گرفته شده است.
اگرچه فراخوانهای اشتراکگذاری حافظه که قبلاً توضیح داده شد، میتوانند برای اشتراکگذاری بافرهای داده مجازی از مهمان به میزبان استفاده شوند، این اشتراکگذاری لزوماً با جزئیات صفحه انجام میشود و اگر اندازه بافر کمتر از اندازه یک صفحه باشد، ممکن است دادههای بیشتری از آنچه لازم است در معرض نمایش بگذارد. . درعوض، مهمان پیکربندی شده است تا هم صفات و هم بافرهای داده مربوط به آنها را از یک پنجره ثابت حافظه مشترک تخصیص دهد، و در صورت لزوم، داده ها به پنجره و از پنجره کپی می شوند.
تعامل با TrustZone
اگرچه مهمانان قادر به تعامل مستقیم با TrustZone نیستند، میزبان همچنان باید بتواند تماس های SMC را به دنیای امن صادر کند. این تماسها میتوانند بافرهای حافظه با آدرس فیزیکی را مشخص کنند که برای میزبان غیرقابل دسترسی هستند. از آنجایی که نرم افزار امن به طور کلی از دسترسی به بافر بی اطلاع است، یک میزبان مخرب می تواند از این بافر برای انجام یک حمله معاون اشتباه (مشابه حمله DMA) استفاده کند. برای جلوگیری از چنین حملاتی، pKVM تمام تماس های SMC میزبان را به EL2 به دام می اندازد و به عنوان یک پروکسی بین میزبان و مانیتور امن در EL3 عمل می کند.
تماسهای PSCI از میزبان با حداقل تغییرات به سیستم عامل EL3 هدایت میشوند. به طور خاص، نقطه ورود برای یک CPU که آنلاین می شود یا از حالت تعلیق دوباره شروع می شود، بازنویسی می شود تا جدول صفحه مرحله 2 قبل از بازگشت به میزبان در EL1 در EL2 نصب شود. در هنگام بوت، این حفاظت توسط pKVM اعمال می شود.
این معماری مبتنی بر SoC است که از PSCI پشتیبانی می کند، ترجیحاً از طریق استفاده از نسخه به روز TF-A به عنوان سیستم عامل EL3 آن.
Firmware Framework for Arm (FF-A) تعاملات بین دنیای عادی و امن را استاندارد می کند، به ویژه در حضور یک هایپروایزر ایمن. بخش عمده ای از مشخصات مکانیزمی را برای به اشتراک گذاری حافظه با دنیای امن، با استفاده از یک قالب پیام مشترک و یک مدل مجوزهای تعریف شده برای صفحات زیرین، تعریف می کند. pKVM پیام های FF-A را پراکسی می کند تا اطمینان حاصل کند که میزبان سعی نمی کند حافظه را با سمت امنی که مجوزهای کافی برای آن ندارد به اشتراک بگذارد.
این معماری متکی به نرم افزار دنیای امن است که مدل دسترسی به حافظه را اعمال می کند، تا اطمینان حاصل کند که برنامه های مورد اعتماد و هر نرم افزار دیگری که در دنیای امن اجرا می شود تنها در صورتی می توانند به حافظه دسترسی داشته باشند که منحصراً متعلق به دنیای امن باشد یا به طور صریح با استفاده از FF با آن به اشتراک گذاشته شده باشد. -الف در سیستمی با S-EL2، اجرای مدل دسترسی به حافظه باید توسط یک هسته مدیر پارتیشن امن (SPMC) مانند Hafnium انجام شود که جداول صفحه مرحله 2 را برای دنیای امن نگهداری می کند. در یک سیستم بدون S-EL2، TEE می تواند در عوض یک مدل دسترسی به حافظه را از طریق جداول صفحه مرحله 1 خود اعمال کند.
اگر تماس SMC به EL2 یک تماس PSCI یا پیام تعریف شده FF-A نباشد، SMC های کنترل نشده به EL3 هدایت می شوند. فرض بر این است که سفتافزار ایمن (الزاماً قابل اعتماد) میتواند SMCهای کنترلنشده را با خیال راحت مدیریت کند، زیرا میانافزار اقدامات احتیاطی لازم برای حفظ ایزولهسازی pVM را درک میکند.
مانیتور ماشین مجازی
crosvm یک مانیتور ماشین مجازی (VMM) است که ماشین های مجازی را از طریق رابط KVM لینوکس اجرا می کند. چیزی که crosvm را منحصر به فرد می کند تمرکز آن بر ایمنی با استفاده از زبان برنامه نویسی Rust و یک جعبه شنی در اطراف دستگاه های مجازی برای محافظت از هسته میزبان است. برای اطلاعات بیشتر در مورد crosvm، اسناد رسمی آن را اینجا ببینید.
توصیفگرهای فایل و ioctls
KVM دستگاه کاراکتر /dev/kvm
را با ioctlهایی که KVM API را تشکیل میدهند در معرض فضای کاربران قرار میدهد. ioctls به دسته های زیر تعلق دارند:
- سیستم ioctls پرس و جو می کند و ویژگی های جهانی را تنظیم می کند که بر کل زیرسیستم KVM تأثیر می گذارد و pVM ها را ایجاد می کند.
- VM ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که CPU های مجازی (vCPU) و دستگاه ها را ایجاد می کنند و کل pVM را تحت تأثیر قرار می دهند، مانند طرح بندی حافظه و تعداد CPU های مجازی (vCPU) و دستگاه ها.
- vCPU ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که عملکرد یک CPU مجازی را کنترل می کند.
- دستگاه ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که عملکرد یک دستگاه مجازی را کنترل می کند.
هر فرآیند crosvm دقیقاً یک نمونه از یک ماشین مجازی را اجرا می کند. این فرآیند از سیستم KVM_CREATE_VM
ioctl برای ایجاد یک توصیفگر فایل VM استفاده می کند که می تواند برای صدور ioctl pVM استفاده شود. یک KVM_CREATE_VCPU
یا KVM_CREATE_DEVICE
ioctl در VM FD یک vCPU/دستگاه ایجاد میکند و یک توصیفگر فایل را برمیگرداند که به منبع جدید اشاره میکند. ioctls در vCPU یا دستگاه FD را می توان برای کنترل دستگاهی که با استفاده از ioctl روی VM FD ایجاد شده است، استفاده کرد. برای vCPU ها، این شامل وظیفه مهم اجرای کد مهمان است.
در داخل، crosvm توصیفگرهای فایل VM را با هسته با استفاده از رابط epoll
با edge-triggered ثبت میکند. سپس کرنل هر زمان که رویداد جدیدی در هر یک از توصیفگرهای پرونده وجود داشته باشد، به crosvm اطلاع می دهد.
pKVM یک قابلیت جدید به KVM_CAP_ARM_PROTECTED_VM
اضافه می کند که می تواند برای دریافت اطلاعات در مورد محیط pVM و تنظیم حالت محافظت شده برای یک ماشین مجازی استفاده شود. اگر پرچم --protected-vm
پاس داده شود، crosvm از این در هنگام ایجاد pVM استفاده می کند تا مقدار مناسب حافظه را برای سیستم عامل pVM پرس و جو کرده و ذخیره کند و سپس حالت محافظت شده را فعال کند.
تخصیص حافظه
یکی از وظایف اصلی VMM تخصیص حافظه VM و مدیریت چیدمان حافظه آن است. crosvm یک چیدمان حافظه ثابت ایجاد می کند که در جدول زیر توضیح داده شده است.
FDT در حالت عادی | PHYS_MEMORY_END - 0x200000 |
فضای آزاد | ... |
رامدیسک | ALIGN_UP(KERNEL_END, 0x1000000) |
هسته | 0x80080000 |
بوت لودر | 0x80200000 |
FDT در حالت BIOS | 0x80000000 |
پایه حافظه فیزیکی | 0x80000000 |
سیستم عامل pVM | 0x7FE00000 |
حافظه دستگاه | 0x10000 - 0x40000000 |
حافظه فیزیکی با mmap
تخصیص داده می شود و حافظه به VM اهدا می شود تا مناطق حافظه آن، به نام memslots ، با ioctl KVM_SET_USER_MEMORY_REGION
پر شود. بنابراین، تمام حافظه pVM مهمان به نمونه crosvm نسبت داده می شود که آن را مدیریت می کند و می تواند منجر به از بین رفتن فرآیند (خاتمه VM) شود اگر میزبان شروع به اتمام حافظه آزاد کند. هنگامی که یک VM متوقف می شود، حافظه به طور خودکار توسط Hypervisor پاک می شود و به هسته میزبان باز می گردد.
تحت KVM معمولی، VMM دسترسی به تمام حافظه مهمان را حفظ می کند. با pKVM، زمانی که حافظه مهمان به مهمان اهدا می شود، از فضای آدرس فیزیکی میزبان خارج می شود. تنها استثنا حافظه ای است که به صراحت توسط مهمان به اشتراک گذاشته می شود، مانند دستگاه های virtio.
مناطق MMIO در فضای آدرس مهمان بدون نقشه باقی می مانند. دسترسی مهمان به این مناطق به دام افتاده و منجر به یک رویداد I/O در VM FD می شود. این مکانیزم برای پیاده سازی دستگاه های مجازی استفاده می شود. در حالت محافظت شده، مهمان باید تصدیق کند که ناحیه ای از فضای آدرسش برای MMIO با استفاده از فراخوانی استفاده می شود تا خطر نشت تصادفی اطلاعات کاهش یابد.
برنامه ریزی
هر CPU مجازی توسط یک رشته POSIX نمایش داده می شود و توسط زمانبندی لینوکس میزبان برنامه ریزی می شود. این رشته، ioctl KVM_RUN
را در VCPU FD فراخوانی میکند، که در نتیجه Hypervisor به زمینه vCPU مهمان سوئیچ میکند. زمانبندی میزبان زمان صرف شده در زمینه مهمان را به عنوان زمان استفاده شده توسط رشته vCPU مربوطه محاسبه می کند. هنگامی که رویدادی وجود دارد که باید توسط VMM مدیریت شود، KVM_RUN
برمی گردد، مانند I/O، پایان وقفه، یا vCPU متوقف شده است. VMM رویداد را مدیریت می کند و دوباره KVM_RUN
فراخوانی می کند.
در طول KVM_RUN
، رشته توسط زمانبندی میزبان قابل پیشگیری باقی میماند، به جز برای اجرای کد هایپروایزر EL2، که قابل پیشگیری نیست. خود pVM مهمان هیچ مکانیزمی برای کنترل این رفتار ندارد.
از آنجایی که تمام رشتههای vCPU مانند سایر وظایف فضای کاربر برنامهریزی شدهاند، تابع تمام مکانیزمهای QoS استاندارد هستند. به طور خاص، هر رشته vCPU را می توان به CPU های فیزیکی متصل کرد، در cpusets قرار داد، با استفاده از گیره استفاده تقویت یا درپوش گذاشت، سیاست اولویت/زمان بندی آنها تغییر کرد و موارد دیگر.
دستگاه های مجازی
crosvm تعدادی دستگاه از جمله موارد زیر را پشتیبانی می کند:
- virtio-blk برای تصاویر دیسک کامپوزیت، فقط خواندنی یا خواندنی-نوشتنی
- vhost-vsock برای ارتباط با میزبان
- virtio-pci به عنوان انتقال virtio
- ساعت واقعی pl030 (RTC)
- 16550a UART برای ارتباط سریال
سیستم عامل pVM
سیستم عامل pVM (pvmfw) اولین کدی است که توسط یک pVM اجرا می شود، شبیه به رام بوت یک دستگاه فیزیکی. هدف اصلی pvmfw این است که بوت امن را بوت استرپ کند و راز منحصر به فرد pVM را استخراج کند. pvmfw به استفاده از سیستم عامل خاصی مانند Microdroid محدود نمی شود، تا زمانی که سیستم عامل توسط crosvm پشتیبانی می شود و به درستی امضا شده است.
باینری pvmfw در یک پارتیشن فلش به همین نام ذخیره می شود و با استفاده از OTA به روز می شود.
بوت دستگاه
دنباله مراحل زیر به رویه بوت دستگاه دارای pKVM اضافه می شود:
- Bootloader Android (ABL) pvmfw را از پارتیشن خود در حافظه بارگیری می کند و تصویر را تأیید می کند.
- ABL اسرار Device Identifier Composition Engine (DICE) خود (شناسه های دستگاه ترکیبی (CDI) و زنجیره گواهی DICE) را از یک Root of Trust بدست می آورد.
- ABL CDI های لازم برای pvmfw را استخراج می کند و آنها را به باینری pvmfw اضافه می کند.
- ABL یک گره حافظه ذخیره شده
linux,pkvm-guest-firmware-memory
به DT اضافه می کند که مکان و اندازه باینری pvmfw و رازهایی را که در مرحله قبل به دست آورده است را توصیف می کند. - ABL کنترل را به لینوکس می دهد و لینوکس pKVM را مقداردهی اولیه می کند.
- pKVM منطقه حافظه pvmfw را از جداول صفحه مرحله 2 میزبان باز می کند و از آن در برابر میزبان (و مهمانان) در طول زمان کارکرد دستگاه محافظت می کند.
پس از بوت شدن دستگاه، Microdroid طبق مراحل در بخش Boot sequence سند Microdroid بوت می شود.
بوت pVM
هنگام ایجاد یک pVM، crosvm (یا VMM دیگر) باید یک مم اسلات به اندازه کافی بزرگ ایجاد کند تا توسط Hypervisor با تصویر pvmfw پر شود. VMM همچنین در لیست رجیسترهایی که می تواند مقدار اولیه آنها را تنظیم کند محدود شده است (x0-x14 برای vCPU اولیه، هیچ برای vCPU های ثانویه). رجیسترهای باقی مانده رزرو شده و بخشی از hypervisor-pvmfw ABI هستند.
هنگامی که pVM اجرا می شود، هایپروایزر ابتدا کنترل vCPU اولیه را به pvmfw می دهد. سفتافزار انتظار دارد که crosvm یک هسته با امضای AVB، که میتواند یک بوتلودر یا هر تصویر دیگری باشد، و یک FDT بدون علامت در حافظه با آفستهای شناختهشده، بارگذاری کند. pvmfw امضای AVB را تأیید می کند و در صورت موفقیت، یک درخت دستگاه قابل اعتماد از FDT دریافتی ایجاد می کند، اسرار آن را از حافظه پاک می کند و به نقطه ورودی بار منشعب می شود. اگر یکی از مراحل تأیید ناموفق باشد، سیستم عامل یک فراخوانی PSCI SYSTEM_RESET
صادر می کند.
بین راهاندازیها، اطلاعات مربوط به نمونه pVM در یک پارتیشن (دستگاه virtio-blk) ذخیره میشود و با رمز pvmfw رمزگذاری میشود تا اطمینان حاصل شود که پس از راهاندازی مجدد، راز به نمونه صحیح ارائه میشود.