معماری AVF

با مجموعه‌ها، منظم بمانید ذخیره و دسته‌بندی محتوا براساس اولویت‌های شما.

اندروید یک پیاده سازی مرجع از تمام اجزای مورد نیاز برای پیاده سازی چارچوب مجازی سازی اندروید ارائه می کند. در حال حاضر این پیاده سازی به 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 در شکل 1 نشان داده شده است. اولین مرحله برای بوت لودر این است که یک هسته لینوکس دارای pKVM را در EL2 وارد کند. در طول راه‌اندازی اولیه، هسته تشخیص می‌دهد که در EL2 در حال اجرا است، خود را از EL1 محروم می‌کند و pKVM را پشت سر می‌گذارد. از این مرحله به بعد، هسته لینوکس به طور عادی بوت می شود و تمام درایورهای دستگاه لازم را بارگیری می کند تا به فضای کاربر برسد. این مراحل زمانی اتفاق می افتد که تحت کنترل pKVM است.

رویه بوت به بوت لودر اعتماد می کند که یکپارچگی تصویر هسته را فقط در طول راه اندازی اولیه حفظ کند. هنگامی که هسته محروم می شود، دیگر توسط هایپروایزر قابل اعتماد تلقی نمی شود، که پس از آن مسئول محافظت از خود حتی اگر هسته در معرض خطر قرار گرفته باشد.

روش بوت pKVM

شکل 1. روش بوت pKVM

وجود هسته اندروید و هایپروایزر در یک تصویر باینری یک رابط ارتباطی بسیار محکم بین آنها ایجاد می کند. این اتصال محکم به روز رسانی اتمی دو جزء را تضمین می کند، که از نیاز به پایدار نگه داشتن رابط بین آنها جلوگیری می کند و انعطاف پذیری زیادی را بدون به خطر انداختن قابلیت نگهداری طولانی مدت ارائه می دهد. کوپلینگ محکم همچنین زمانی که هر دو مؤلفه می توانند بدون تأثیر بر تضمین های امنیتی ارائه شده توسط هایپروایزر با یکدیگر همکاری کنند، امکان بهینه سازی عملکرد را فراهم می کند.

علاوه بر این، پذیرش GKI در اکوسیستم اندروید به طور خودکار به هایپروایزر pKVM اجازه می دهد تا در دستگاه های اندرویدی به صورت باینری مشابه هسته مستقر شود.

حفاظت از دسترسی به حافظه CPU

معماری Arm یک واحد مدیریت حافظه (MMU) را به دو مرحله مستقل تقسیم می‌کند، که هر دو می‌توانند برای پیاده‌سازی ترجمه آدرس و کنترل دسترسی به بخش‌های مختلف حافظه استفاده شوند. مرحله 1 MMU توسط EL1 کنترل می شود و سطح اول ترجمه آدرس را امکان پذیر می کند. مرحله 1 MMU توسط لینوکس برای مدیریت فضای آدرس مجازی ارائه شده به هر فرآیند فضای کاربر و فضای آدرس مجازی خود استفاده می شود.

مرحله 2 MMU توسط EL2 کنترل می شود و استفاده از ترجمه آدرس دوم را در آدرس خروجی MMU مرحله 1 امکان پذیر می کند که منجر به یک آدرس فیزیکی (PA) می شود. ترجمه مرحله 2 می تواند توسط هایپروایزرها برای کنترل و ترجمه دسترسی های حافظه از تمام ماشین های مجازی مهمان استفاده شود. همانطور که در شکل 2 نشان داده شده است، زمانی که هر دو مرحله ترجمه فعال هستند، آدرس خروجی مرحله 1 یک آدرس فیزیکی متوسط ​​(IPA) نامیده می شود. توجه: آدرس مجازی (VA) به یک IPA و سپس به یک PA ترجمه می شود.

حفاظت از دسترسی به حافظه CPU

شکل 2. حفاظت از دسترسی به حافظه CPU

از لحاظ تاریخی، 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 نشان داده شده است، نیاز دارد.

حفاظت از دسترسی به حافظه DMA

شکل 3. حفاظت از دسترسی به حافظه DMA

حداقل، سخت‌افزار IOMMU ابزاری را برای اعطا و لغو دسترسی خواندن/نوشتن برای دستگاه به حافظه فیزیکی با جزئیات صفحه فراهم می‌کند. با این حال، این سخت‌افزار IOMMU استفاده از دستگاه‌ها را در pVM محدود می‌کند، زیرا آن‌ها مرحله 2 نقشه‌برداری هویتی را فرض می‌کنند.

برای اطمینان از جداسازی بین ماشین های مجازی، تراکنش های حافظه ایجاد شده از طرف نهادهای مختلف باید توسط IOMMU قابل تشخیص باشند تا بتوان از مجموعه مناسب جداول صفحه برای ترجمه استفاده کرد.

علاوه بر این، کاهش مقدار کد اختصاصی SoC در EL2 یک استراتژی کلیدی برای کاهش پایه محاسباتی قابل اعتماد کلی (TCB) pKVM است و برخلاف گنجاندن درایورهای IOMMU در هایپروایزر است. برای کاهش این مشکل، میزبان در EL1 مسئول وظایف مدیریت کمکی IOMMU، مانند مدیریت توان، مقداردهی اولیه و در صورت لزوم، مدیریت وقفه است.

با این حال، قرار دادن میزبان در کنترل وضعیت دستگاه، الزامات بیشتری را در رابط برنامه‌نویسی سخت‌افزار IOMMU ایجاد می‌کند تا اطمینان حاصل شود که بررسی‌های مجوز را نمی‌توان با روش‌های دیگری دور زد، به عنوان مثال، پس از بازنشانی دستگاه.

یک IOMMU استاندارد و به خوبی پشتیبانی شده برای دستگاه‌های بازویی که هم جداسازی و هم انتساب مستقیم را ممکن می‌سازد، معماری واحد مدیریت حافظه سیستم بازو (SMMU) است. این معماری راه حل مرجع توصیه شده است.

مالکیت حافظه

در زمان راه‌اندازی، فرض می‌شود که تمام حافظه غیرهایپروایزر متعلق به میزبان است و به همین ترتیب توسط هایپروایزر ردیابی می‌شود. هنگامی که یک pVM ایجاد می‌شود، میزبان صفحات حافظه را اهدا می‌کند تا به آن اجازه راه‌اندازی داده شود و هایپروایزر مالکیت آن صفحات را از میزبان به pVM منتقل می‌کند. بنابراین، هایپروایزر محدودیت‌های کنترل دسترسی را در جدول صفحه مرحله 2 میزبان اعمال می‌کند تا از دسترسی مجدد به صفحات جلوگیری کند و محرمانه بودن را برای مهمان فراهم کند.

ارتباط بین میزبان و مهمانان با به اشتراک گذاری حافظه کنترل شده بین آنها امکان پذیر می شود. مهمانان مجاز هستند برخی از صفحات خود را با استفاده از فراخوانی با میزبان به اشتراک بگذارند، که به هایپروایزر دستور می دهد تا آن صفحات را در جدول صفحه میزبان مرحله 2 مجدداً نقشه برداری کند. به طور مشابه، ارتباط میزبان با TrustZone با عملیات اشتراک گذاری حافظه و/یا امانت امکان پذیر می شود، که همه آنها به دقت توسط pKVM با استفاده از مشخصات فریمور فریمورک برای بازو (FF-A) نظارت و کنترل می شوند.

هایپروایزر مسئول ردیابی مالکیت تمام صفحات حافظه در سیستم و اینکه آیا آنها به اشتراک گذاشته می شوند یا به نهادهای دیگر قرض داده می شوند، است. بیشتر این ردیابی وضعیت با استفاده از ابرداده های پیوست شده به جداول صفحه میزبان و مهمانان مرحله 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

  • اشتراک گذاری حافظه با میزبان تمام حافظه مهمان در ابتدا برای میزبان غیرقابل دسترسی است، اما دسترسی میزبان برای ارتباط با حافظه مشترک و برای دستگاه‌های مجازی‌سازی شده که به بافرهای مشترک متکی هستند، ضروری است. فراخوانی برای اشتراک‌گذاری و لغو اشتراک‌گذاری صفحات با میزبان به مهمان این امکان را می‌دهد تا بدون نیاز به دست دادن دقیقاً تصمیم بگیرد که چه بخش‌هایی از حافظه برای بقیه اندروید قابل دسترسی است.
  • به دام انداختن دسترسی به حافظه برای میزبان. به طور سنتی، اگر یک مهمان KVM به آدرسی دسترسی پیدا کند که با یک منطقه حافظه معتبر مطابقت ندارد، رشته vCPU به میزبان خارج می شود و دسترسی معمولاً برای MMIO استفاده می شود و توسط VMM در فضای کاربر شبیه سازی می شود. برای تسهیل این کار، pKVM باید جزئیات دستورالعمل خطا مانند آدرس، پارامترهای ثبت و احتمالاً محتویات آنها را به میزبان بازگرداند، که اگر تله پیش بینی نشده باشد، می تواند ناخواسته داده های حساس یک مهمان محافظت شده را در معرض دید قرار دهد. pKVM این مشکل را با تلقی کردن این خطاها به‌عنوان کشنده حل می‌کند، مگر اینکه مهمان قبلاً یک فراخوانی برای شناسایی محدوده IPA معیوب به عنوان محدوده‌ای که دسترسی‌ها مجاز است به میزبان بازگردانده شود، صادر کرده باشد. این راه حل به عنوان محافظ MMIO شناخته می شود.

دستگاه ورودی/خروجی مجازی (virtio)

Virtio یک استاندارد محبوب، قابل حمل و بالغ برای پیاده سازی و تعامل با دستگاه های paravirtualized است. اکثر دستگاه هایی که در معرض مهمانان محافظت شده قرار می گیرند با استفاده از virtio اجرا می شوند. Virtio همچنین زیربنای اجرای vsock است که برای ارتباط بین مهمان محافظت شده و بقیه اندروید استفاده می شود.

دستگاه‌های Virtio معمولاً در فضای کاربر میزبان توسط VMM پیاده‌سازی می‌شوند، که دسترسی‌های حافظه به دام افتاده را از مهمان به رابط MMIO دستگاه virtio رهگیری می‌کند و رفتار مورد انتظار را شبیه‌سازی می‌کند. دسترسی MMIO نسبتاً گران است زیرا هر دسترسی به دستگاه نیاز به یک رفت و برگشت به VMM و برگشت دارد، بنابراین بیشتر انتقال داده واقعی بین دستگاه و مهمان با استفاده از مجموعه‌ای از صفات در حافظه انجام می‌شود. یک فرض کلیدی virtio این است که میزبان می تواند خودسرانه به حافظه مهمان دسترسی داشته باشد. این فرض در طراحی virtqueue مشهود است، که ممکن است حاوی نشانگرهایی به بافرهایی در مهمان باشد که شبیه سازی دستگاه برای دسترسی مستقیم به آنها در نظر گرفته شده است.

اگرچه فراخوان‌های اشتراک‌گذاری حافظه که قبلاً توضیح داده شد، می‌توانند برای اشتراک‌گذاری بافرهای داده مجازی از مهمان به میزبان استفاده شوند، این اشتراک‌گذاری لزوماً با جزئیات صفحه انجام می‌شود و اگر اندازه بافر کمتر از اندازه یک صفحه باشد، ممکن است داده‌های بیشتری از آنچه لازم است در معرض نمایش بگذارد. . درعوض، مهمان پیکربندی شده است تا هم صفات و هم بافرهای داده مربوط به آنها را از یک پنجره ثابت حافظه مشترک تخصیص دهد، و در صورت لزوم، داده ها به پنجره و از پنجره کپی می شوند.

دستگاه مجازی

شکل 4. دستگاه Virtio

تعامل با 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 و یک جعبه شنی در اطراف دستگاه های مجازی برای محافظت از هسته میزبان است.

توصیفگرهای فایل و ioctls

KVM دستگاه کاراکتر /dev/kvm kvm را با ioctlهایی که KVM API را تشکیل می‌دهند در معرض فضای کاربران قرار می‌دهد. ioctls به دسته های زیر تعلق دارند:

  • سیستم ioctls پرس و جو می کند و ویژگی های جهانی را تنظیم می کند که بر کل زیرسیستم KVM تأثیر می گذارد و pVM ها را ایجاد می کند.
  • VM ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که CPU های مجازی (vCPU) و دستگاه ها را ایجاد می کنند و کل pVM را تحت تأثیر قرار می دهند، مانند طرح بندی حافظه و تعداد CPU های مجازی (vCPU) و دستگاه ها.
  • vCPU ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که عملکرد یک CPU مجازی را کنترل می کند.
  • دستگاه ioctls پرس و جو می کند و ویژگی هایی را تنظیم می کند که عملکرد یک دستگاه مجازی را کنترل می کند.

هر فرآیند crosvm دقیقاً یک نمونه از یک ماشین مجازی را اجرا می کند. این فرآیند از سیستم KVM_CREATE_VM برای ایجاد یک توصیفگر فایل VM استفاده می کند که می تواند برای صدور ioctl pVM استفاده شود. یک KVM_CREATE_VCPU یا KVM_CREATE_DEVICE در 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 ، با KVM_SET_USER_MEMORY_REGION شود. بنابراین، تمام حافظه pVM مهمان به نمونه crosvm نسبت داده می شود که آن را مدیریت می کند و می تواند منجر به از بین رفتن فرآیند (خاتمه VM) شود اگر میزبان شروع به اتمام حافظه آزاد کند. هنگامی که یک VM متوقف می شود، حافظه به طور خودکار توسط Hypervisor پاک می شود و به هسته میزبان باز می گردد.

تحت KVM معمولی، VMM دسترسی به تمام حافظه مهمان را حفظ می کند. با pKVM، زمانی که حافظه مهمان به مهمان اهدا می شود، از فضای آدرس فیزیکی میزبان خارج می شود. تنها استثنا حافظه ای است که به صراحت توسط مهمان به اشتراک گذاشته می شود، مانند دستگاه های virtio.

مناطق MMIO در فضای آدرس مهمان بدون نقشه باقی می مانند. دسترسی مهمان به این مناطق به دام افتاده و منجر به یک رویداد I/O در VM FD می شود. این مکانیزم برای پیاده سازی دستگاه های مجازی استفاده می شود. در حالت محافظت شده، مهمان باید تصدیق کند که ناحیه ای از فضای آدرسش برای MMIO با استفاده از فراخوانی استفاده می شود تا خطر نشت تصادفی اطلاعات کاهش یابد.

برنامه ریزی

هر CPU مجازی توسط یک رشته POSIX نمایش داده می شود و توسط زمانبندی لینوکس میزبان برنامه ریزی می شود. این رشته، 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 اضافه می شود:

  1. Bootloader Android (ABL) pvmfw را از پارتیشن خود در حافظه بارگیری می کند و تصویر را تأیید می کند.
  2. ABL اسرار Device Identifier Composition Engine (DICE) خود (شناسه های دستگاه ترکیبی (CDI) و زنجیره گواهی راه اندازی (BCC)) را از یک Root of Trust بدست می آورد.
  3. ABL اندازه گیری و استخراج DICE اسرار pvmfw (CDI) را انجام می دهد و آنها را به باینری pvmfw اضافه می کند.
  4. ABL یک گره حافظه linux,pkvm-guest-firmware-memory را به DT اضافه می‌کند و مکان و اندازه باینری pvmfw و اسرار آن را در مرحله قبل توصیف می‌کند.
  5. ABL کنترل را به لینوکس می دهد و لینوکس pKVM را مقداردهی اولیه می کند.
  6. 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 دریافتی تولید می‌کند، اسرار آن را از حافظه پاک می‌کند و به نقطه ورودی بار منشعب می‌شود. اگر یکی از مراحل تأیید ناموفق باشد، سیستم عامل یک فراخوانی SYSTEM_RESET SYSTEM_RESET صادر می کند.

بین راه‌اندازی‌ها، اطلاعات مربوط به نمونه pVM در یک پارتیشن (دستگاه virtio-blk) ذخیره می‌شود و با رمز pvmfw رمزگذاری می‌شود تا اطمینان حاصل شود که پس از راه‌اندازی مجدد، راز به نمونه صحیح ارائه می‌شود.