ארכיטקטורת AVF

אנדרואיד מספקת יישום ייחוס של כל הרכיבים הדרושים ליישום מסגרת הוירטואליזציה של אנדרואיד. כרגע יישום זה מוגבל ל-ARM64. דף זה מסביר את ארכיטקטורת המסגרת.

רקע כללי

ארכיטקטורת Arm מאפשרת עד ארבע רמות חריגים, כאשר רמת חריג 0 (EL0) היא הכי פחות מועדפת, ורמת חריג 3 (EL3) הכי הרבה. החלק הגדול ביותר של בסיס הקוד של אנדרואיד (כל רכיבי מרחב המשתמש) פועל ב-EL0. שאר מה שנהוג לכנות "אנדרואיד" הוא ליבת לינוקס, שפועלת ב-EL1.

שכבת EL2 מאפשרת הכנסת היפרוויזר המאפשר לבודד זיכרון והתקנים ל-pVMs בודדים ב-EL1/EL0, עם הבטחות סודיות ויושרה חזקות.

היפרוויזר

המכונה הווירטואלית המוגנת מבוססת ליבה (pKVM) בנויה על ה- Linux KVM hypervisor , אשר הורחב עם היכולת להגביל את הגישה לעומסים הפועלים במכונות וירטואליות אורחות המסומנות כ'מוגנות' בזמן היצירה.

KVM/arm64 תומך במצבי הפעלה שונים בהתאם לזמינות של תכונות מעבד מסוימות, כלומר, הרחבות מארח וירטואליזציה (VHE) (ARMv8.1 ואילך). באחד מהמצבים הללו, הידוע בדרך כלל כמצב שאינו VHE, קוד ה-Hypervisor מחולק מתמונת הליבה במהלך האתחול ומותקן ב-EL2, בעוד שהקרנל עצמו פועל ב-EL1. למרות שהוא חלק מבסיס הקוד של לינוקס, רכיב EL2 של KVM הוא רכיב קטן שאחראי על המעבר בין מספר EL1s, ונשלט לחלוטין על ידי הליבה של המארח. רכיב ה-Hypervisor מורכב עם לינוקס, אך נמצא בקטע זיכרון נפרד, ייעודי של תמונת vmlinux . pKVM ממנפת את העיצוב הזה על ידי הרחבת קוד ה-Hypervisor עם תכונות חדשות המאפשרות לו לשים הגבלות על ליבת המארח של אנדרואיד ועל שטח המשתמש, והגבלת גישת המארח לזיכרון האורח וה-Hypervisor.

מודולי ספק pKVM

מודול ספק pKVM הוא מודול ספציפי לחומרה המכיל פונקציונליות ספציפית למכשיר, כגון מנהלי התקנים של יחידת ניהול זיכרון קלט-פלט (IOMMU). מודולים אלה מאפשרים לך להעביר תכונות אבטחה הדורשות גישה חריגה ברמה 2 (EL2) ל-pKVM.

כדי ללמוד כיצד ליישם ולטעון מודול ספק pKVM, עיין ביישום מודול ספק pKVM .

הליך אתחול

האיור הבא מתאר את הליך האתחול של pKVM:

הליך אתחול pKVM

איור 1. הליך אתחול pKVM

  1. טוען האתחול נכנס לליבה הגנרית ב-EL2.
  2. הליבה הגנרית מזהה שהוא פועל ב-EL2 ומחסל את עצמו ל-EL1 בעוד pKVM והמודולים שלו ממשיכים לפעול ב-EL2. בנוסף, מודולים של ספקי pKVM נטענים בשלב זה.
  3. הליבה הגנרית ממשיכה לאתחל כרגיל, תוך שהיא טוענת את כל מנהלי ההתקנים הדרושים עד שמגיעים למרחב המשתמש. בשלב זה, pKVM נמצא במקום ומטפל בטבלאות העמודים בשלב 2.

הליך האתחול סומך על טוען האתחול שישמור על שלמות תמונת הליבה רק במהלך האתחול המוקדם. כאשר הליבה מושבתת, הוא כבר לא נחשב אמין על ידי ה-Hypervisor, אשר לאחר מכן אחראי להגן על עצמו גם אם הליבה נפגעת.

קיום ליבת האנדרואיד וה-Hypervisor באותה תמונה בינארית מאפשרת ממשק תקשורת צמוד מאוד ביניהם. צימוד הדוק זה מבטיח עדכונים אטומיים של שני הרכיבים, מה שמונע את הצורך לשמור על יציבות הממשק ביניהם, ומציע גמישות רבה מבלי לפגוע בתחזוקה ארוכת טווח. הצימוד ההדוק מאפשר גם אופטימיזציות של ביצועים כאשר שני הרכיבים יכולים לשתף פעולה מבלי להשפיע על ערבויות האבטחה שמספק ה-Hypervisor.

יתרה מכך, האימוץ של GKI במערכת האקולוגית של אנדרואיד מאפשר פריסה אוטומטית של ה-pKVM hypervisor למכשירי אנדרואיד באותו בינארי כמו הליבה.

הגנת גישה לזיכרון המעבד

ארכיטקטורת Arm מציינת יחידת ניהול זיכרון (MMU) המפוצלת בשני שלבים בלתי תלויים, אשר בשניהם ניתן להשתמש כדי ליישם תרגום כתובות ובקרת גישה לחלקים שונים של הזיכרון. ה-MMU שלב 1 נשלט על ידי EL1 ומאפשר רמה ראשונה של תרגום כתובות. MMU שלב 1 משמש את לינוקס לניהול מרחב הכתובות הווירטואלי המסופק לכל תהליך מרחב משתמש ולמרחב הכתובות הווירטואלי שלו.

שלב 2 MMU נשלט על ידי EL2 ומאפשר יישום של תרגום כתובת שני על כתובת הפלט של שלב 1 MMU, וכתוצאה מכך כתובת פיזית (PA). התרגום של שלב 2 יכול לשמש על ידי היפרוויזורים כדי לשלוט ולתרגם גישה לזיכרון מכל ה-VMs האורחים. כפי שמוצג באיור 2, כאשר שני שלבי התרגום מופעלים, כתובת הפלט של שלב 1 נקראת כתובת פיזית ביניים (IPA). הערה: הכתובת הוירטואלית (VA) מתורגמת ל-IPA ולאחר מכן ל-PA.

הגנת גישה לזיכרון המעבד

איור 2. הגנת גישה לזיכרון המעבד

מבחינה היסטורית, KVM פועל עם תרגום שלב 2 מופעל בזמן הפעלת אורחים ועם שלב 2 מושבת בזמן הפעלת ליבת לינוקס המארח. ארכיטקטורה זו מאפשרת לגישות לזיכרון מה-MMU של שלב 1 המארח לעבור דרך MMU של שלב 2, ומכאן שמאפשרת גישה בלתי מוגבלת מהמארח לדפי זיכרון אורח. מצד שני, pKVM מאפשר הגנה בשלב 2 גם בהקשר מארח, ומציב את ה-Hypervisor אחראי על הגנה על דפי זיכרון אורחים במקום המארח.

KVM עושה שימוש מלא בתרגום כתובות בשלב 2 כדי ליישם מיפוי IPA/PA מורכב לאורחים, מה שיוצר אשליה של זיכרון רציף לאורחים למרות פיצול פיזי. עם זאת, השימוש ב-MMU שלב 2 עבור המארח מוגבל לבקרת גישה בלבד. שלב המארח 2 ממופה זהות, מה שמבטיח שזיכרון רציף במרחב IPA המארח רציף במרחב ה-PA. ארכיטקטורה זו מאפשרת שימוש במיפויים גדולים בטבלת הדפים, וכתוצאה מכך מפחיתה את הלחץ על מאגר התרגום מבט-צדדי (TLB). מכיוון שניתן להוסיף מיפוי זהות לאינדקס על ידי הרשות הפלסטינית, שלב 2 המארח משמש גם למעקב אחר בעלות על דף ישירות בטבלת הדפים.

הגנת גישה ישירה לזיכרון (DMA).

כפי שתואר קודם לכן, ביטול מיפוי של דפי אורח ממארח ​​לינוקס בטבלאות דפי CPU הוא צעד הכרחי אך לא מספיק להגנה על זיכרון אורח. pKVM צריך גם להגן מפני גישה לזיכרון שנעשו על ידי התקנים בעלי יכולת DMA תחת שליטת ליבת המארח, והאפשרות של מתקפת DMA יזומה על ידי מארח זדוני. כדי למנוע מהתקן כזה לגשת לזיכרון אורח, pKVM דורשת חומרה של יחידת ניהול זיכרון קלט-פלט (IOMMU) עבור כל התקן בעל יכולת DMA במערכת, כפי שמוצג באיור 3.

הגנת גישה לזיכרון Dma

איור 3. הגנת גישה לזיכרון DMA

לכל הפחות, חומרת IOMMU מספקת את האמצעים להענקה ולביטול גישת קריאה/כתיבה של התקן לזיכרון פיזי ברמת פירוט הדפים. עם זאת, חומרת IOMMU זו מגבילה את השימוש בהתקנים ב-pVMs מכיוון שהם מניחים שלב 2 ממופה זהות.

כדי להבטיח בידוד בין מכונות וירטואליות, עסקאות זיכרון שנוצרו מטעם ישויות שונות חייבות להיות ניתנות להבחנה על ידי IOMMU כך שניתן יהיה להשתמש בסט המתאים של טבלאות עמודים לתרגום.

בנוסף, הפחתת כמות הקוד הספציפי ל-SoC ב-EL2 היא אסטרטגיית מפתח להפחתת בסיס המחשוב המהימן הכולל (TCB) של pKVM ומנוגדת להכללה של מנהלי התקנים של IOMMU ב-Hypervisor. כדי להקל על בעיה זו, המארח ב-EL1 אחראי על משימות עזר לניהול IOMMU, כגון ניהול צריכת חשמל, אתחול, ובמידת הצורך, טיפול בהפרעות.

עם זאת, העמדת המארח בשליטה על מצב המכשיר מציבה דרישות נוספות על ממשק התכנות של החומרה של IOMMU כדי להבטיח שלא ניתן לעקוף בדיקות הרשאות באמצעים אחרים, למשל, בעקבות איפוס מכשיר.

IOMMU סטנדרטי ונתמך היטב עבור התקני Arm שמאפשר גם בידוד וגם הקצאה ישירה הוא ארכיטקטורת Arm System Memory Management Unit (SMMU). ארכיטקטורה זו היא פתרון ההתייחסות המומלץ.

בעלות על זיכרון

בזמן האתחול, ההנחה היא שכל הזיכרון שאינו היפרוויזר נמצא בבעלות המארח, והוא עוקב ככזה על ידי ה-Hypervisor. כאשר pVM נוצר, המארח תורם דפי זיכרון כדי לאפשר לו לאתחל וה-hypervisor מעביר את הבעלות על הדפים הללו מהמארח ל-pVM. לפיכך, ה-Hypervisor שם הגבלות בקרת גישה בטבלת הדפים בשלב 2 של המארח כדי למנוע ממנו לגשת שוב לדפים, תוך מתן סודיות לאורח.

התקשורת בין המארח לאורחים מתאפשרת על ידי שיתוף זיכרון מבוקר ביניהם. אורחים רשאים לשתף חלק מהדפים שלהם בחזרה עם המארח באמצעות היפר-קריאה, אשר מורה ל-hypervisor למפות מחדש את הדפים הללו בטבלת הדפים המארח בשלב 2. באופן דומה, התקשורת של המארח עם TrustZone מתאפשרת על ידי פעולות שיתוף ו/או השאלת זיכרון, שכולן מנוטרות ונשלטות מקרוב על ידי pKVM באמצעות מפרט Firmware Framework for Arm (FF-A) .

מכיוון שדרישות הזיכרון של pVM יכולות להשתנות עם הזמן, ניתנת היפר-קריאה המאפשרת לוותר על בעלות על דפים שצוינו השייכים למתקשר בחזרה למארח. בפועל משתמשים בהיפר-קריאה זו עם פרוטוקול הבלון של virtio כדי לאפשר ל-VMM לבקש זיכרון בחזרה מה-pVM, ול-pVM להודיע ​​ל-VMM על עמודים שנמסרו, באופן מבוקר.

ה-Hypervisor אחראי למעקב אחר הבעלות על כל דפי הזיכרון במערכת והאם הם משותפים או מושאלים לגורמים אחרים. רוב מעקב המצב הזה נעשה באמצעות מטא נתונים המצורפים לטבלאות העמודים של המארח והאורחים בשלב 2, תוך שימוש בסיביות שמורות בערכים של טבלת העמודים (PTEs) שכפי ששמם מרמז, שמורות לשימוש בתוכנה.

המארח חייב לוודא שהוא לא ינסה לגשת לדפים שנעשו בלתי נגישים על ידי ה-Hypervisor. גישת מארח לא חוקית גורמת להחדרת חריג סינכרוני למארח על ידי ה-Hypervisor, מה שעלול לגרום למשימת מרחב המשתמש האחראית לקבל אות SEGV, או לקריסת ליבת המארח. כדי למנוע גישה מקרית, דפים שנתרמו לאורחים אינם כשירים להחלפה או מיזוג על ידי הגרעין המארח.

טיפול בפסיקות וטיימרים

פסיקות הן חלק חיוני מהדרך שבה אורח מקיים אינטראקציה עם מכשירים ולתקשורת בין מעבדים, כאשר פסיקות בין מעבדים (IPI) הן מנגנון התקשורת העיקרי. מודל ה-KVM הוא להאציל את כל ניהול ההפסקות הווירטואלי למארח ב-EL1, שלצורך כך מתנהג כחלק לא מהימן מה-Hypervisor.

pKVM מציעה אמולציה מלאה של בקר פסיקה גנרי גרסה 3 (GICv3) המבוססת על קוד ה-KVM הקיים. טיימר ו-IPI מטופלים כחלק מקוד אמולציה לא מהימן זה.

תמיכה ב-GICv3

הממשק בין EL1 ל-EL2 חייב להבטיח שמצב ההפסקה המלא יהיה גלוי למארח EL1, כולל עותקים של אוגרי ההיפרוויזר הקשורים לפסיקות. הנראות הזו מתבצעת בדרך כלל באמצעות אזורי זיכרון משותפים, אחד לכל מעבד וירטואלי (vCPU).

ניתן לפשט את קוד התמיכה בזמן ריצה של רישום המערכת כדי לתמוך רק ב-Software Generated Interrupt Register (SGIR) ו-Deactivate Interrupt Register (DIR). הארכיטקטורה מחייבת שרגיסטרים אלה תמיד מלכודים ל-EL2, בעוד שהמלכודות האחרות עד כה היו שימושיות רק כדי להפחית את התקלות. כל השאר מטופל בחומרה.

בצד MMIO, הכל מחקה ב-EL1, תוך שימוש חוזר בכל התשתית הנוכחית ב-KVM. לבסוף, Wait for Interrupt (WFI) מועבר תמיד ל-EL1, מכיוון שזהו אחד מהפרימיטיביים הבסיסיים של התזמון שבו KVM משתמש.

תמיכה בטיימר

ערך ההשוואה לטיימר הוירטואלי חייב להיות חשוף ל-EL1 בכל WFI לכידה כדי ש-EL1 יוכל להזריק פסיקות טיימר בזמן שה-vCPU חסום. הטיימר הפיזי הוא חיקוי לחלוטין, וכל המלכודות מועברות ל-EL1.

טיפול ב-MMIO

כדי לתקשר עם צג המכונה הווירטואלית (VMM) ולבצע אמולציית GIC, יש להעביר מלכודות MMIO בחזרה למארח ב-EL1 לצורך ניסוי נוסף. pKVM דורש את הדברים הבאים:

  • IPA וגודל הגישה
  • נתונים במקרה של כתיבה
  • סוף המעבד בנקודת לכידה

בנוסף, מלכודות עם אוגר למטרות כלליות (GPR) כמקור/יעד מועברות באמצעות פסאודו-אוגר מופשט של העברה.

ממשקי אורחים

אורח יכול לתקשר עם אורח מוגן באמצעות שילוב של שיחות היפר וגישה לזיכרון לאזורים לכודים. שיחות היפר נחשפות לפי תקן SMCCC , עם טווח שמור להקצאת ספקים על ידי KVM. ההיפר-קריאות הבאות הן בעלות חשיבות מיוחדת לאורחי pKVM.

שיחות היפר גנריות

  • PSCI מספק מנגנון סטנדרטי עבור האורח לשלוט במחזור החיים של ה-vCPUs שלו כולל חיבור מקוון, הפעלה לא מקוון וכיבוי מערכת.
  • TRNG מספק מנגנון סטנדרטי עבור האורח לבקש אנטרופיה מה-pKVM אשר מעביר את השיחה ל-EL3. מנגנון זה שימושי במיוחד כאשר לא ניתן לסמוך על המארח שיעשה וירטואליזציה של מחולל מספרים אקראיים בחומרה (RNG).

היפר-קריאות pKVM

  • שיתוף זיכרון עם המארח. כל זיכרון האורח אינו נגיש בתחילה למארח, אך גישה למארח נחוצה לתקשורת בזיכרון משותף ולמכשירים מוירטואליים המסתמכים על מאגרים משותפים. היפר-קריאות לשיתוף וביטול שיתוף של דפים עם המארח מאפשרות לאורח להחליט בדיוק אילו חלקי זיכרון נעשים נגישים לשאר אנדרואיד ללא צורך בלחיצת יד.
  • ויתור זיכרון למארח. כל זיכרון האורח שייך בדרך כלל לאורח עד שהוא מושמד. מצב זה יכול להיות לא הולם עבור מחשבי VM ארוכים עם דרישות זיכרון המשתנות לאורך זמן. relinquish -קריאה לוויתור מאפשרת לאורח להעביר באופן מפורש בעלות על דפים בחזרה למארח מבלי לדרוש סיום אורח.
  • לכידת גישה לזיכרון למארח. באופן מסורתי, אם אורח KVM ניגש לכתובת שאינה מתאימה לאזור זיכרון חוקי, אז שרשור ה-vCPU יוצא אל המארח והגישה משמשת בדרך כלל עבור MMIO ומחולקת על ידי ה-VMM בחלל המשתמש. כדי להקל על הטיפול הזה, pKVM נדרש לפרסם פרטים על ההוראה התקלה כמו הכתובת שלה, לרשום פרמטרים ואולי את תוכנם בחזרה למארח, מה שעלול לחשוף ללא כוונה נתונים רגישים מאורח מוגן אם המלכודת לא הייתה צפויה. pKVM פותר בעיה זו על ידי התייחסות לתקלות אלו כקטלניות אלא אם האורח הוציא בעבר קריאת היפר כדי לזהות את טווח ה-IPA התקול ככזה שעבורו מותרות גישה ללכוד בחזרה למארח. פתרון זה מכונה שומר MMIO .

מכשיר I/O וירטואלי (ווירטיו)

Virtio הוא תקן פופולרי, נייד ובוגר להטמעה ואינטראקציה עם מכשירים מוירטואליים. רוב המכשירים שנחשפים לאורחים מוגנים מיושמים באמצעות virtio. Virtio גם מהווה בסיס ליישום vsock המשמש לתקשורת בין אורח מוגן לשאר אנדרואיד.

התקני Virtio מיושמים בדרך כלל במרחב המשתמש של המארח על ידי ה-VMM, אשר מיירט גישה לזיכרון כלוא מהאורח לממשק ה-MMIO של התקן הוירטיו ומדמה את ההתנהגות הצפויה. גישת MMIO היא יקרה יחסית מכיוון שכל גישה למכשיר מצריכה נסיעה הלוך ושוב ל-VMM ובחזרה, כך שרוב העברת הנתונים בפועל בין המכשיר לאורח מתרחשת באמצעות קבוצה של virtqueues בזיכרון. הנחת מפתח של virtio היא שהמארח יכול לגשת לזיכרון האורח באופן שרירותי. הנחה זו ניכרת בעיצוב ה-virtqueue, שעשוי להכיל מצביעים למאגרים באורח שאליהם אמולציית המכשיר נועדה לגשת ישירות.

למרות שניתן להשתמש בהיפר-קריאות שיתוף הזיכרון שתוארו קודם כדי לשתף מאגרי נתונים וירטיו מהאורח למארח, שיתוף זה מבוצע בהכרח בפירוט העמוד ועלול בסופו של דבר לחשוף יותר נתונים מהנדרש אם גודל המאגר קטן מזה של עמוד . במקום זאת, האורח מוגדר להקצות הן את ה-virtqueues והן את מאגרי הנתונים המתאימים להם מחלון קבוע של זיכרון משותף, כאשר נתונים מועתקים (מוחזרים) אל החלון וממנו כנדרש.

מכשיר וירטואלי

איור 4. מכשיר Virtio

אינטראקציה עם TrustZone

למרות שאורחים אינם יכולים ליצור אינטראקציה ישירה עם TrustZone, המארח עדיין חייב להיות מסוגל להוציא שיחות SMC לעולם המאובטח. שיחות אלה יכולות לציין מאגרי זיכרון עם מענה פיזי שאינם נגישים למארח. מכיוון שהתוכנה המאובטחת בדרך כלל אינה מודעת לנגישות המאגר, מארח זדוני יכול להשתמש במאגר זה כדי לבצע התקפת סגן מבולבלת (בדומה להתקפת DMA). כדי למנוע התקפות כאלה, pKVM לוכד את כל קריאות SMC המארח ל-EL2 ומתפקד כפרוקסי בין המארח למוניטור המאובטח ב-EL3.

שיחות PSCI מהמארח מועברות לקושחה EL3 עם שינויים מינימליים. באופן ספציפי, נקודת הכניסה של מעבד המגיע למצב מקוון או חוזר מהשעיה נכתבת מחדש כך שטבלת הדפים בשלב 2 מותקנת ב-EL2 לפני החזרה למארח ב-EL1. במהלך האתחול, הגנות זו נאכפת על ידי pKVM.

ארכיטקטורה זו מסתמכת על ה-SoC התומך ב-PSCI, רצוי באמצעות שימוש בגרסה עדכנית של TF-A בתור קושחת EL3.

Firmware Framework for Arm (FF-A) מייצרת אינטראקציות בין העולם הרגיל והמאובטח, במיוחד בנוכחות היפרוויזר מאובטח. חלק עיקרי של המפרט מגדיר מנגנון לשיתוף זיכרון עם העולם המאובטח, תוך שימוש הן בפורמט הודעה משותף והן במודל הרשאות מוגדר היטב עבור העמודים הבסיסיים. pKVM מעביר הודעות פרוקסי FF-A כדי להבטיח שהמארח לא מנסה לשתף זיכרון עם הצד המאובטח שעבורו אין לו הרשאות מספיקות.

ארכיטקטורה זו מסתמכת על תוכנת העולם המאובטח האוכפת את מודל הגישה לזיכרון, כדי להבטיח שאפליקציות מהימנות וכל תוכנה אחרת הפועלת בעולם המאובטח יוכלו לגשת לזיכרון רק אם היא בבעלות בלעדית של העולם המאובטח או שותפה איתו במפורש באמצעות FF -א. במערכת עם S-EL2, אכיפת מודל הגישה לזיכרון צריכה להיעשות על ידי Core Secure Partition Manager (SPMC), כגון Hafnium , ששומרת על טבלאות דפים בשלב 2 עבור העולם המאובטח. במערכת ללא S-EL2, ה-TEE יכול במקום זאת לאכוף מודל גישה לזיכרון דרך טבלאות העמודים שלו בשלב 1.

אם קריאת SMC ל-EL2 אינה שיחת PSCI או הודעה מוגדרת FF-A, SMCs לא מטופלים מועברים ל-EL3. ההנחה היא שהקושחה המאובטחת (המהימנה בהכרח) יכולה להתמודד עם SMCs לא מטופלים בבטחה מכיוון שהקושחה מבינה את אמצעי הזהירות הדרושים לשמירה על בידוד pVM.

צג מכונה וירטואלית

crosvm הוא צג מכונה וירטואלית (VMM) המריץ מכונות וירטואליות דרך ממשק KVM של לינוקס. מה שמייחד את crosvm הוא ההתמקדות שלו בבטיחות עם שימוש בשפת התכנות Rust וארגז חול סביב מכשירים וירטואליים כדי להגן על ליבת המארח. למידע נוסף על crosvm, עיין בתיעוד הרשמי שלה כאן .

מתארי קבצים ו-ioctls

KVM חושף את התקן הדמות /dev/kvm למרחב משתמש עם ioctls המרכיבים את KVM API. ה-ioctls שייכים לקטגוריות הבאות:

  • Ioctls של המערכת מבצעים שאילתות ומגדירים תכונות גלובליות המשפיעות על כל תת-מערכת ה-KVM, ויוצרות pVMs.
  • VM ioctls מבצעים שאילתות ומגדירות תכונות היוצרות מעבדים וירטואליים (vCPUs) והתקנים, ומשפיעות על pVM שלם, כגון כולל פריסת זיכרון ומספר המעבדים הווירטואליים (vCPUs) והתקנים.
  • vCPU ioctls מבצעים שאילתה ומגדירה תכונות השולטות בפעולת מעבד וירטואלי יחיד.
  • התקן ioctls מבצע שאילתות ומגדיר תכונות השולטות בפעולה של מכשיר וירטואלי יחיד.

כל תהליך crosvm מריץ מופע אחד בדיוק של מכונה וירטואלית. תהליך זה משתמש במערכת KVM_CREATE_VM ioctl כדי ליצור מתאר קובץ VM שניתן להשתמש בו כדי להנפיק ioctls של pVM. KVM_CREATE_VCPU או KVM_CREATE_DEVICE ioctl ב-VM FD יוצר vCPU/מכשיר ומחזיר מתאר קובץ המצביע על המשאב החדש. ניתן להשתמש ב-ioctls ב-vCPU או ב-FD של התקן כדי לשלוט במכשיר שנוצר באמצעות ioctl ב-VM FD. עבור vCPUs, זה כולל את המשימה החשובה של הפעלת קוד אורח.

באופן פנימי, crosvm רושם את מתארי הקבצים של ה-VM עם הליבה באמצעות ממשק epoll המופעל על ידי קצה. לאחר מכן, הקרנל מודיע ל-crosvm בכל פעם שיש אירוע חדש בהמתנה בכל אחד מתארי הקבצים.

pKVM מוסיף יכולת חדשה, KVM_CAP_ARM_PROTECTED_VM , שניתן להשתמש בה כדי לקבל מידע על סביבת ה-pVM ולהגדיר מצב מוגן עבור VM. crosvm משתמש בזה במהלך יצירת pVM אם הדגל --protected-vm מועבר, כדי לשאול ולשמור את כמות הזיכרון המתאימה עבור קושחת 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, זיכרון האורח אינו ממופה ממרחב הכתובות הפיזיות של המארח כאשר הוא נתרם לאורח. היוצא מן הכלל היחיד הוא זיכרון המשותף במפורש על ידי האורח, כגון עבור התקני וירטיו.

אזורי MMIO במרחב הכתובות של האורח נותרים ללא מיפוי. הגישה לאזורים אלו על ידי האורח נלכדת וגורמת לאירוע I/O ב-VM FD. מנגנון זה משמש ליישום מכשירים וירטואליים. במצב מוגן, על האורח לאשר שאזור במרחב הכתובות שלו משמש עבור MMIO באמצעות היפר-call, כדי להפחית את הסיכון לדליפת מידע מקרית.

תזמון

כל מעבד וירטואלי מיוצג על ידי שרשור POSIX ומתוזמן על ידי מתזמן Linux המארח. השרשור קורא ל- KVM_RUN ioctl ב-vCPU FD, וכתוצאה מכך ה-Hypervisor עובר להקשר ה-vCPU האורח. מתזמן המארח מתייחס לזמן שהוקדש בהקשר אורח כזמן המשמש את שרשור ה-vCPU המתאים. KVM_RUN חוזר כאשר יש אירוע שחייב להיות מטופל על ידי ה-VMM, כגון I/O, end of interrupt, או עצירת ה-vCPU. ה-VMM מטפל באירוע וקורא ל- KVM_RUN שוב.

במהלך KVM_RUN , השרשור נשאר מונע על ידי מתזמן המארח, למעט ביצוע קוד ה-Hypervisor EL2, שאינו ניתן לביטול. ל-pVM האורח עצמו אין מנגנון לשליטה בהתנהגות זו.

מכיוון שכל שרשורי ה-vCPU מתוזמנים כמו כל משימות אחרות של מרחב המשתמש, הם כפופים לכל מנגנוני ה-QoS הסטנדרטיים. באופן ספציפי, ניתן לשייך כל פתיל vCPU למעבדים פיזיים, למקם בערכות cpus, להגביר או להגביל באמצעות הידוק ניצול, לשנות את מדיניות העדיפות/תזמון שלהם ועוד.

מכשירים וירטואליים

crosvm תומך במספר מכשירים, כולל המכשירים הבאים:

  • virtio-blk עבור תמונות דיסק מורכב, לקריאה בלבד או קריאה-כתיבה
  • vhost-vsock לתקשורת עם המארח
  • virtio-pci כ-virtio transport
  • pl030 שעון זמן אמת (RTC)
  • 16550a UART לתקשורת טורית

קושחה של pVM

הקושחה של pVM (pvmfw) היא הקוד הראשון שמבוצע על ידי pVM, בדומה לאתחול ROM של מכשיר פיזי. המטרה העיקרית של pvmfw היא לאתחל אתחול מאובטח ולהפיק את הסוד הייחודי של ה-pVM. pvmfw אינו מוגבל לשימוש עם מערכת הפעלה ספציפית כלשהי, כגון Microdroid , כל עוד מערכת ההפעלה נתמכת על ידי crosvm ונחתמה כהלכה.

הקובץ הבינארי pvmfw מאוחסן במחיצת פלאש באותו שם ומתעדכן באמצעות OTA .

אתחול המכשיר

רצף השלבים הבא מתווסף לנוהל האתחול של התקן התומך pKVM:

  1. ה-Android Bootloader (ABL) טוען את pvmfw מהמחיצה שלו לזיכרון ומאמת את התמונה.
  2. ה-ABL משיג את סודות מנוע ההרכבה של זיהוי ההתקנים (DICE) שלו (מזהי התקנים מורכבים (CDI) ושרשרת אישורי האתחול (BCC)) משורש אמון.
  3. ה-ABL מבצע מדידה וגזירת DICE של סודות pvmfw (CDIs), ומצרף אותם ל-pvmfw הבינארי.
  4. ה-ABL מוסיף ל-DT צומת אזור זיכרון שמור linux,pkvm-guest-firmware-memory , המתאר את המיקום והגודל של הבינארי pvmfw ואת הסודות שהוא הפיק בשלב הקודם.
  5. ה-ABL מעביר את השליטה ללינוקס ולינוקס מאתחל את pKVM.
  6. pKVM מבטל את מיפוי אזור הזיכרון של pvmfw מטבלאות הדפים בשלב 2 של המארח ומגן עליו מפני המארח (ואורחים) לאורך זמן פעילות המכשיר.

לאחר אתחול המכשיר, Microdroid מופעל לפי השלבים בסעיף רצף האתחול של מסמך Microdroid .

אתחול pVM

בעת יצירת pVM, crosvm (או VMM אחר) חייב ליצור משבצת זיכרון גדולה מספיק כדי להיות מאוכלס בתמונת pvmfw על ידי ה-Hypervisor. ה-VMM מוגבל גם ברשימת האוגרים שאת הערך ההתחלתי שלהם הוא יכול להגדיר (x0-x14 עבור ה-vCPU הראשי, אין עבור vCPUs משני). הרישומים הנותרים שמורים והם חלק מה-hypervisor-pvmfw ABI.

כאשר ה-pVM מופעל, ה-Hypervisor מעביר תחילה את השליטה על ה-vCPU הראשי ל-pvmfw. הקושחה מצפה של crosvm לטעון ליבה חתומה על AVB, שיכול להיות טוען אתחול או כל תמונה אחרת, ו-FDT לא חתום לזיכרון בהיסטים ידועים. pvmfw מאמת את חתימת ה-AVB, ואם מצליח, מייצר עץ התקן מהימן מה-FDT שהתקבל, מוחק את סודותיו מהזיכרון ומסתעף לנקודת הכניסה של המטען. אם אחד משלבי האימות נכשל, הקושחה מוציאה היפר-קריאה PSCI SYSTEM_RESET .

בין האתחולים, מידע על מופע ה-pVM מאוחסן במחיצה (מכשיר virtio-blk) ומוצפן בסוד של pvmfw כדי להבטיח שבעקבות אתחול מחדש, הסוד יועבר למופע הנכון.