Android cung cấp triển khai tham chiếu cho tất cả các thành phần cần thiết để triển khai Android Virtualization Framework. Hiện tại, việc triển khai này được giới hạn ở ARM64. Trang này giải thích kiến trúc khung.
Lý lịch
Kiến trúc Arm cho phép tối đa bốn cấp ngoại lệ, với cấp ngoại lệ 0 (EL0) là cấp ít đặc quyền nhất và cấp ngoại lệ 3 (EL3) là nhiều nhất. Phần lớn nhất của cơ sở mã Android (tất cả các thành phần không gian người dùng) chạy ở EL0. Phần còn lại của cái thường được gọi là "Android" là nhân Linux, chạy ở EL1.
Lớp EL2 cho phép giới thiệu một trình ảo hóa cho phép cách ly bộ nhớ và thiết bị thành các pVM riêng lẻ tại EL1/EL0, với các đảm bảo toàn vẹn và bảo mật mạnh mẽ.
siêu giám sát
Máy ảo dựa trên nhân được bảo vệ (pKVM) được xây dựng dựa trên trình ảo hóa KVM của Linux , đã được mở rộng với khả năng hạn chế quyền truy cập vào các tải trọng đang chạy trong các máy ảo khách được đánh dấu 'được bảo vệ' tại thời điểm tạo.
KVM/arm64 hỗ trợ các chế độ thực thi khác nhau tùy thuộc vào tính khả dụng của một số tính năng CPU nhất định, cụ thể là Phần mở rộng máy chủ ảo hóa (VHE) (ARMv8.1 trở lên). Ở một trong các chế độ đó, thường được gọi là chế độ không phải VHE, mã trình ảo hóa được tách ra khỏi hình ảnh nhân trong khi khởi động và được cài đặt ở EL2, trong khi bản thân nhân chạy ở EL1. Mặc dù là một phần của cơ sở mã Linux, thành phần EL2 của KVM là một thành phần nhỏ chịu trách nhiệm chuyển đổi giữa nhiều EL1 và được kiểm soát hoàn toàn bởi nhân của máy chủ. Thành phần trình ảo hóa được biên dịch bằng Linux, nhưng nằm trong một phần bộ nhớ chuyên dụng, riêng biệt của hình ảnh vmlinux
. pKVM tận dụng thiết kế này bằng cách mở rộng mã trình ảo hóa với các tính năng mới cho phép nó đặt các hạn chế đối với nhân máy chủ Android và không gian người dùng, đồng thời hạn chế quyền truy cập của máy chủ vào bộ nhớ khách và trình ảo hóa.
thủ tục khởi động
Quy trình khởi động pKVM được mô tả trong hình 1. Bước đầu tiên là bộ tải khởi động nhập nhân Linux hỗ trợ pKVM tại EL2. Trong quá trình khởi động sớm, kernel phát hiện ra rằng nó đang chạy ở EL2, tự tước quyền của EL1, để lại pKVM. Từ thời điểm này, nhân Linux tiến hành khởi động bình thường, tải tất cả các trình điều khiển thiết bị cần thiết, cho đến khi đạt đến không gian người dùng. Các bước này xảy ra trong khi dưới sự kiểm soát của pKVM.
Quy trình khởi động tin cậy bộ tải khởi động để duy trì tính toàn vẹn của hình ảnh hạt nhân chỉ trong thời gian khởi động sớm. Khi hạt nhân bị tước quyền, nó không còn được coi là đáng tin cậy bởi trình ảo hóa, sau đó chịu trách nhiệm bảo vệ chính nó ngay cả khi hạt nhân bị xâm phạm.
Việc có nhân Android và trình ảo hóa trong cùng một hình ảnh nhị phân cho phép giao diện liên lạc được kết hợp rất chặt chẽ giữa chúng. Sự kết hợp chặt chẽ này đảm bảo các bản cập nhật nguyên tử của hai thành phần, giúp tránh nhu cầu giữ cho giao diện giữa chúng ổn định và mang lại sự linh hoạt cao mà không ảnh hưởng đến khả năng bảo trì lâu dài. Sự kết hợp chặt chẽ cũng cho phép tối ưu hóa hiệu suất khi cả hai thành phần có thể hợp tác mà không ảnh hưởng đến các đảm bảo an ninh do trình ảo hóa cung cấp.
Ngoài ra, việc áp dụng GKI trong hệ sinh thái Android sẽ tự động cho phép triển khai trình ảo hóa pKVM cho các thiết bị Android ở cùng dạng nhị phân với nhân.
Bảo vệ truy cập bộ nhớ CPU
Kiến trúc Arm chỉ định chia đơn vị quản lý bộ nhớ (MMU) thành hai giai đoạn độc lập, cả hai đều có thể được sử dụng để thực hiện dịch địa chỉ và kiểm soát truy cập vào các phần khác nhau của bộ nhớ. MMU giai đoạn 1 được điều khiển bởi EL1 và cho phép dịch địa chỉ cấp đầu tiên. MMU giai đoạn 1 được Linux sử dụng để quản lý không gian địa chỉ ảo được cung cấp cho từng quy trình không gian người dùng và không gian địa chỉ ảo của chính nó.
MMU giai đoạn 2 được điều khiển bởi EL2 và cho phép ứng dụng dịch địa chỉ thứ hai trên địa chỉ đầu ra của MMU giai đoạn 1, dẫn đến địa chỉ vật lý (PA). Bản dịch giai đoạn 2 có thể được sử dụng bởi các trình ảo hóa để kiểm soát và dịch các truy cập bộ nhớ từ tất cả các máy ảo khách. Như thể hiện trong hình 2, khi cả hai giai đoạn dịch được kích hoạt, địa chỉ đầu ra của giai đoạn 1 được gọi là địa chỉ vật lý trung gian (IPA) Lưu ý: Địa chỉ ảo (VA) được dịch thành IPA và sau đó thành PA.
Về mặt lịch sử, KVM chạy với tính năng dịch giai đoạn 2 được bật khi chạy máy khách và tắt giai đoạn 2 khi chạy nhân Linux máy chủ. Kiến trúc này cho phép truy cập bộ nhớ từ MMU giai đoạn 1 của máy chủ đi qua MMU giai đoạn 2, do đó cho phép truy cập không hạn chế từ máy chủ đến các trang bộ nhớ khách. Mặt khác, pKVM cho phép bảo vệ giai đoạn 2 ngay cả trong ngữ cảnh máy chủ và đặt trình ảo hóa chịu trách nhiệm bảo vệ các trang bộ nhớ khách thay vì máy chủ.
KVM tận dụng tối đa việc dịch địa chỉ ở giai đoạn 2 để triển khai ánh xạ IPA/PA phức tạp cho khách, điều này tạo ảo giác về bộ nhớ liền kề cho khách mặc dù có sự phân mảnh vật lý. Tuy nhiên, việc sử dụng MMU giai đoạn 2 cho máy chủ chỉ bị hạn chế đối với kiểm soát truy cập. Giai đoạn máy chủ 2 được ánh xạ nhận dạng, đảm bảo rằng bộ nhớ liền kề trong không gian IPA máy chủ tiếp giáp trong không gian PA. Kiến trúc này cho phép sử dụng các ánh xạ lớn trong bảng trang và do đó làm giảm áp lực lên bộ đệm tra cứu dịch thuật (TLB). Do ánh xạ nhận dạng có thể được lập chỉ mục bởi PA, máy chủ lưu trữ giai đoạn 2 cũng được sử dụng để theo dõi quyền sở hữu trang trực tiếp trong bảng trang.
Bảo vệ truy cập bộ nhớ trực tiếp (DMA)
Như đã mô tả trước đây, hủy ánh xạ các trang khách từ máy chủ Linux trong bảng trang CPU là bước cần thiết nhưng chưa đủ để bảo vệ bộ nhớ khách. pKVM cũng cần bảo vệ chống lại các truy cập bộ nhớ do các thiết bị có khả năng DMA thực hiện dưới sự kiểm soát của nhân máy chủ và khả năng xảy ra cuộc tấn công DMA do máy chủ độc hại khởi xướng. Để ngăn một thiết bị như vậy truy cập bộ nhớ khách, pKVM yêu cầu phần cứng bộ quản lý bộ nhớ đầu vào-đầu ra (IOMMU) cho mọi thiết bị có khả năng DMA trong hệ thống, như trong hình 3.
Ở mức tối thiểu, phần cứng IOMMU cung cấp phương tiện cấp và thu hồi quyền truy cập đọc/ghi cho thiết bị vào bộ nhớ vật lý ở mức độ chi tiết của trang. Tuy nhiên, phần cứng IOMMU này giới hạn việc sử dụng các thiết bị trong pVM khi chúng giả sử giai đoạn 2 được ánh xạ nhận dạng.
Để đảm bảo cách ly giữa các máy ảo, các giao dịch bộ nhớ được tạo thay mặt cho các thực thể khác nhau phải được IOMMU phân biệt để có thể sử dụng bộ bảng trang thích hợp cho quá trình dịch.
Ngoài ra, việc giảm số lượng mã dành riêng cho SoC tại EL2 là một chiến lược quan trọng để giảm cơ sở điện toán đáng tin cậy tổng thể (TCB) của pKVM và chống lại việc đưa các trình điều khiển IOMMU vào trình ảo hóa. Để giảm thiểu sự cố này, máy chủ tại EL1 chịu trách nhiệm về các tác vụ quản lý IOMMU phụ trợ, chẳng hạn như quản lý năng lượng, khởi tạo và xử lý ngắt khi thích hợp.
Tuy nhiên, việc đặt máy chủ kiểm soát trạng thái thiết bị sẽ đặt ra các yêu cầu bổ sung đối với giao diện lập trình của phần cứng IOMMU để đảm bảo rằng việc kiểm tra quyền không thể bị bỏ qua bằng các cách khác, chẳng hạn như sau khi đặt lại thiết bị.
Một IOMMU tiêu chuẩn và được hỗ trợ tốt cho các thiết bị Arm có thể thực hiện được cả việc cách ly và gán trực tiếp là kiến trúc Đơn vị quản lý bộ nhớ hệ thống Arm (SMMU). Kiến trúc này là giải pháp tham khảo được đề xuất.
Quyền sở hữu bộ nhớ
Tại thời điểm khởi động, tất cả bộ nhớ không phải của trình ảo hóa được coi là thuộc sở hữu của máy chủ và được theo dõi như vậy bởi trình ảo hóa. Khi một pVM được sinh ra, máy chủ tặng các trang bộ nhớ để cho phép nó khởi động và trình ảo hóa sẽ chuyển quyền sở hữu các trang đó từ máy chủ sang pVM. Do đó, trình ảo hóa đặt các hạn chế kiểm soát truy cập vào bảng trang giai đoạn 2 của máy chủ để ngăn nó truy cập lại các trang, cung cấp tính bảo mật cho khách.
Giao tiếp giữa máy chủ và khách được thực hiện bằng cách chia sẻ bộ nhớ có kiểm soát giữa họ. Khách được phép chia sẻ lại một số trang của họ với máy chủ lưu trữ bằng cách sử dụng siêu lệnh gọi, siêu lệnh gọi này hướng dẫn trình ảo hóa sắp xếp lại các trang đó trong bảng trang giai đoạn 2 của máy chủ. Tương tự, giao tiếp của máy chủ với TrustZone có thể thực hiện được nhờ các hoạt động chia sẻ và/hoặc cho mượn bộ nhớ, tất cả đều được pKVM giám sát và kiểm soát chặt chẽ bằng cách sử dụng đặc tả Khung chương trình cơ sở cho Arm (FF-A) .
Trình ảo hóa chịu trách nhiệm theo dõi quyền sở hữu của tất cả các trang bộ nhớ trong hệ thống và liệu chúng có đang được chia sẻ hoặc cho các thực thể khác mượn hay không. Hầu hết việc theo dõi trạng thái này được thực hiện bằng cách sử dụng siêu dữ liệu được đính kèm với các bảng trang giai đoạn 2 của máy chủ và khách, sử dụng các bit dành riêng trong các mục nhập bảng trang (PTE), như tên gọi của chúng, được dành riêng cho việc sử dụng phần mềm.
Máy chủ lưu trữ phải đảm bảo rằng nó không cố gắng truy cập các trang mà trình ảo hóa không thể truy cập được. Quyền truy cập máy chủ bất hợp pháp khiến trình ảo hóa đưa một ngoại lệ đồng bộ vào máy chủ, điều này có thể dẫn đến tác vụ không gian người dùng chịu trách nhiệm nhận tín hiệu SEGV hoặc nhân máy chủ gặp sự cố. Để ngăn chặn các truy cập tình cờ, các trang được cung cấp cho khách sẽ không đủ điều kiện để hoán đổi hoặc hợp nhất bởi nhân máy chủ.
Xử lý ngắt và hẹn giờ
Ngắt là một phần thiết yếu trong cách khách tương tác với các thiết bị và để giao tiếp giữa các CPU, trong đó ngắt giữa các bộ xử lý (IPI) là cơ chế giao tiếp chính. Mô hình KVM sẽ ủy quyền tất cả việc quản lý ngắt ảo cho máy chủ trong EL1, vì mục đích đó hoạt động như một phần không đáng tin cậy của trình ảo hóa.
pKVM cung cấp mô phỏng Bộ điều khiển ngắt chung phiên bản 3 (GICv3) đầy đủ dựa trên mã KVM hiện có. Bộ hẹn giờ và IPI được xử lý như một phần của mã mô phỏng không đáng tin cậy này.
hỗ trợ GICv3
Giao diện giữa EL1 và EL2 phải đảm bảo rằng máy chủ EL1 có thể nhìn thấy toàn bộ trạng thái ngắt, bao gồm các bản sao của thanh ghi trình ảo hóa liên quan đến ngắt. Khả năng hiển thị này thường được thực hiện bằng cách sử dụng các vùng bộ nhớ dùng chung, một vùng cho mỗi CPU ảo (vCPU).
Mã hỗ trợ thời gian chạy thanh ghi hệ thống có thể được đơn giản hóa để chỉ hỗ trợ bẫy thanh ghi Thanh ghi ngắt do phần mềm tạo (SGIR) và Hủy kích hoạt thanh ghi ngắt (DIR). Kiến trúc yêu cầu các thanh ghi này luôn bẫy EL2, trong khi các bẫy khác cho đến nay chỉ hữu ích để giảm thiểu lỗi. Mọi thứ khác đang được xử lý trong phần cứng.
Về phía MMIO, mọi thứ được mô phỏng tại EL1, sử dụng lại tất cả cơ sở hạ tầng hiện tại trong KVM. Cuối cùng, Chờ ngắt (WFI) luôn được chuyển tiếp đến EL1, bởi vì đây là một trong những nguyên tắc lập lịch cơ bản mà KVM sử dụng.
hỗ trợ hẹn giờ
Giá trị bộ so sánh cho bộ hẹn giờ ảo phải được hiển thị với EL1 trên mỗi WFI bẫy để EL1 có thể thực hiện các ngắt của bộ hẹn giờ trong khi vCPU bị chặn. Bộ hẹn giờ vật lý được mô phỏng hoàn toàn và tất cả các bẫy được chuyển tiếp đến EL1.
xử lý MMIO
Để giao tiếp với màn hình máy ảo (VMM) và thực hiện mô phỏng GIC, các bẫy MMIO phải được chuyển tiếp trở lại máy chủ trong EL1 để xử lý thêm. pKVM yêu cầu như sau:
- IPA và kích thước của quyền truy cập
- Dữ liệu trong trường hợp ghi
- Độ bền của CPU tại điểm bẫy
Ngoài ra, các bẫy có thanh ghi mục đích chung (GPR) làm nguồn/đích được chuyển tiếp bằng cách sử dụng thanh ghi giả chuyển giao trừu tượng.
giao diện khách
Một khách có thể giao tiếp với một khách được bảo vệ bằng cách sử dụng kết hợp siêu cuộc gọi và truy cập bộ nhớ vào các vùng bị bẫy. Hypercalls được hiển thị theo tiêu chuẩn SMCCC , với phạm vi dành riêng cho phân bổ nhà cung cấp của KVM. Các siêu cuộc gọi sau đây có tầm quan trọng đặc biệt đối với khách pKVM.
Siêu cuộc gọi chung
- PSCI cung cấp một cơ chế tiêu chuẩn để khách kiểm soát vòng đời của các vCPU của mình bao gồm trực tuyến, ngoại tuyến và tắt hệ thống.
- TRNG cung cấp một cơ chế tiêu chuẩn để khách yêu cầu entropy từ pKVM chuyển tiếp cuộc gọi đến EL3. Cơ chế này đặc biệt hữu ích khi không thể tin cậy máy chủ để ảo hóa bộ tạo số ngẫu nhiên phần cứng (RNG).
siêu gọi pKVM
- Chia sẻ bộ nhớ với máy chủ. Tất cả bộ nhớ khách ban đầu không thể truy cập được vào máy chủ, nhưng quyền truy cập máy chủ là cần thiết cho giao tiếp bộ nhớ dùng chung và cho các thiết bị ảo hóa dựa trên bộ đệm dùng chung. Các cuộc gọi siêu tốc để chia sẻ và hủy chia sẻ các trang với máy chủ lưu trữ cho phép khách quyết định chính xác phần bộ nhớ nào được phép truy cập vào phần còn lại của Android mà không cần bắt tay.
- Bẫy truy cập bộ nhớ đến máy chủ. Theo truyền thống, nếu khách KVM truy cập địa chỉ không tương ứng với vùng bộ nhớ hợp lệ thì chuỗi vCPU sẽ thoát ra máy chủ và quyền truy cập thường được sử dụng cho MMIO và được mô phỏng bởi VMM trong không gian người dùng. Để tạo điều kiện thuận lợi cho việc xử lý này, pKVM được yêu cầu quảng cáo chi tiết về hướng dẫn bị lỗi, chẳng hạn như địa chỉ, tham số đăng ký và có khả năng là nội dung của chúng trở lại máy chủ, điều này có thể vô tình làm lộ dữ liệu nhạy cảm từ khách được bảo vệ nếu không lường trước được bẫy. pKVM giải quyết vấn đề này bằng cách coi các lỗi này là lỗi nghiêm trọng trừ khi khách trước đó đã đưa ra siêu lệnh gọi để xác định phạm vi IPA bị lỗi là phạm vi mà quyền truy cập được phép truy cập trở lại máy chủ. Giải pháp này được gọi là bảo vệ MMIO .
Thiết bị I/O ảo (virtio)
Virtio là một tiêu chuẩn phổ biến, di động và trưởng thành để triển khai và tương tác với các thiết bị ảo hóa. Phần lớn các thiết bị tiếp xúc với khách được bảo vệ được triển khai bằng virtio. Virtio cũng củng cố việc triển khai vsock được sử dụng để liên lạc giữa một khách được bảo vệ và phần còn lại của Android.
Các thiết bị Virtio thường được VMM triển khai trong không gian người dùng của máy chủ, ngăn chặn các truy cập bộ nhớ bị mắc kẹt từ khách đến giao diện MMIO của thiết bị Virtio và mô phỏng hành vi dự kiến. Truy cập MMIO tương đối tốn kém vì mỗi lần truy cập vào thiết bị yêu cầu một chuyến đi khứ hồi đến VMM và ngược lại, do đó, hầu hết quá trình truyền dữ liệu thực tế giữa thiết bị và khách diễn ra bằng cách sử dụng một tập hợp các hàng đợi hiệu quả trong bộ nhớ. Một giả định chính của virtio là máy chủ có thể truy cập bộ nhớ khách một cách tùy ý. Giả định này thể hiện rõ ràng trong thiết kế của hàng thủ công, có thể chứa các con trỏ tới bộ đệm trong máy khách mà mô phỏng thiết bị nhằm mục đích truy cập trực tiếp.
Mặc dù các siêu lệnh chia sẻ bộ nhớ được mô tả trước đây có thể được sử dụng để chia sẻ bộ đệm dữ liệu hiệu quả từ máy khách đến máy chủ, nhưng việc chia sẻ này nhất thiết phải được thực hiện ở mức độ chi tiết của trang và cuối cùng có thể làm lộ nhiều dữ liệu hơn mức cần thiết nếu kích thước bộ đệm nhỏ hơn kích thước của một trang . Thay vào đó, khách được định cấu hình để phân bổ cả hàng thủ công và bộ đệm dữ liệu tương ứng của chúng từ một cửa sổ cố định của bộ nhớ dùng chung, với dữ liệu được sao chép (được trả lại) đến và từ cửa sổ theo yêu cầu.
Tương tác với TrustZone
Mặc dù khách không thể tương tác trực tiếp với TrustZone, máy chủ lưu trữ vẫn phải có khả năng thực hiện các cuộc gọi SMC vào thế giới an toàn. Các cuộc gọi này có thể chỉ định bộ đệm bộ nhớ được xử lý vật lý mà máy chủ không thể truy cập được. Bởi vì phần mềm bảo mật thường không biết về khả năng truy cập của bộ đệm, máy chủ độc hại có thể sử dụng bộ đệm này để thực hiện một cuộc tấn công nhầm lẫn (tương tự như một cuộc tấn công DMA). Để ngăn chặn các cuộc tấn công như vậy, pKVM bẫy tất cả các cuộc gọi SMC của máy chủ tới EL2 và hoạt động như một proxy giữa máy chủ và màn hình an toàn tại EL3.
Các cuộc gọi PSCI từ máy chủ được chuyển tiếp đến phần sụn EL3 với các sửa đổi tối thiểu. Cụ thể, điểm vào cho CPU sắp trực tuyến hoặc tiếp tục sau khi tạm dừng được viết lại để bảng trang giai đoạn 2 được cài đặt tại EL2 trước khi quay lại máy chủ tại EL1. Trong quá trình khởi động, biện pháp bảo vệ này được thực thi bởi pKVM.
Kiến trúc này dựa trên SoC hỗ trợ PSCI, tốt nhất là thông qua việc sử dụng phiên bản cập nhật của TF-A làm phần sụn EL3 của nó.
Khung chương trình cơ sở cho Arm (FF-A) chuẩn hóa các tương tác giữa thế giới bình thường và thế giới an toàn, đặc biệt là khi có một trình ảo hóa an toàn. Phần chính của đặc tả xác định cơ chế chia sẻ bộ nhớ với thế giới bảo mật, sử dụng cả định dạng thông báo chung và mô hình quyền được xác định rõ cho các trang bên dưới. pKVM ủy quyền các thông báo FF-A để đảm bảo rằng máy chủ không cố gắng chia sẻ bộ nhớ với phía bảo mật mà nó không có đủ quyền.
Kiến trúc này dựa trên phần mềm thế giới bảo mật thực thi mô hình truy cập bộ nhớ, để đảm bảo rằng các ứng dụng đáng tin cậy và bất kỳ phần mềm nào khác chạy trong thế giới bảo mật chỉ có thể truy cập bộ nhớ nếu nó thuộc sở hữu độc quyền của thế giới bảo mật hoặc đã được chia sẻ rõ ràng với nó bằng FF -MỘT. Trên hệ thống có S-EL2, việc thực thi mô hình truy cập bộ nhớ phải được thực hiện bởi Lõi quản lý phân vùng an toàn (SPMC), chẳng hạn như Hafnium , duy trì các bảng trang giai đoạn 2 cho thế giới bảo mật. Trên một hệ thống không có S-EL2, thay vào đó, TEE có thể thực thi mô hình truy cập bộ nhớ thông qua các bảng trang giai đoạn 1 của nó.
Nếu cuộc gọi SMC tới EL2 không phải là cuộc gọi PSCI hoặc thông báo được xác định bởi FF-A, thì các SMC chưa được xử lý sẽ được chuyển tiếp tới EL3. Giả định là phần sụn bảo mật (nhất thiết phải đáng tin cậy) có thể xử lý các SMC chưa được xử lý một cách an toàn vì phần sụn hiểu các biện pháp phòng ngừa cần thiết để duy trì cách ly pVM.
Màn hình máy ảo
crosvm là một trình theo dõi máy ảo (VMM) chạy các máy ảo thông qua giao diện KVM của Linux. Điều làm cho crosvm trở nên độc đáo là nó tập trung vào tính an toàn với việc sử dụng ngôn ngữ lập trình Rust và hộp cát xung quanh các thiết bị ảo để bảo vệ nhân máy chủ.
Bộ mô tả tệp và ioctls
KVM hiển thị thiết bị ký tự /dev/kvm
cho không gian người dùng với ioctls tạo nên API KVM. Các ioctls thuộc các danh mục sau:
- Truy vấn ioctls hệ thống và đặt các thuộc tính toàn cầu ảnh hưởng đến toàn bộ hệ thống con KVM và tạo pVM.
- VM ioctls truy vấn và thiết lập các thuộc tính tạo CPU ảo (vCPU) và thiết bị, đồng thời ảnh hưởng đến toàn bộ pVM, chẳng hạn như bao gồm bố cục bộ nhớ và số lượng CPU ảo (vCPU) và thiết bị.
- vCPU ioctls truy vấn và thiết lập các thuộc tính kiểm soát hoạt động của một CPU ảo duy nhất.
- Truy vấn ioctls của thiết bị và đặt các thuộc tính kiểm soát hoạt động của một thiết bị ảo.
Mỗi quy trình crosvm chạy chính xác một phiên bản của máy ảo. Quá trình này sử dụng ioctl hệ thống KVM_CREATE_VM
để tạo một bộ mô tả tệp VM có thể được sử dụng để phát hành ioctls pVM. KVM_CREATE_VCPU
hoặc KVM_CREATE_DEVICE
ioctl trên VM FD tạo một vCPU/thiết bị và trả về một bộ mô tả tệp trỏ đến tài nguyên mới. ioctls trên vCPU hoặc FD thiết bị có thể được sử dụng để điều khiển thiết bị được tạo bằng ioctl trên VM FD. Đối với vCPU, điều này bao gồm nhiệm vụ quan trọng là chạy mã khách.
Bên trong, crosvm đăng ký các bộ mô tả tệp của VM với kernel bằng giao diện epoll
kích hoạt cạnh. Sau đó, hạt nhân sẽ thông báo cho crosvm bất cứ khi nào có một sự kiện mới đang chờ xử lý trong bất kỳ bộ mô tả tệp nào.
pKVM thêm một khả năng mới, KVM_CAP_ARM_PROTECTED_VM
, có thể được sử dụng để lấy thông tin về môi trường pVM và thiết lập chế độ được bảo vệ cho máy ảo. crosvm sử dụng điều này trong quá trình tạo pVM nếu cờ --protected-vm
được thông qua, để truy vấn và dự trữ lượng bộ nhớ thích hợp cho chương trình cơ sở pVM, sau đó để bật chế độ được bảo vệ.
Cấp phát bộ nhớ
Một trong những trách nhiệm chính của VMM là phân bổ bộ nhớ của VM và quản lý bố cục bộ nhớ của nó. crosvm tạo bố cục bộ nhớ cố định được mô tả lỏng lẻo trong bảng bên dưới.
FDT ở chế độ bình thường | PHYS_MEMORY_END - 0x200000 |
Không gian trông | ... |
đĩa cứng | ALIGN_UP(KERNEL_END, 0x1000000) |
hạt nhân | 0x80080000 |
bộ nạp khởi động | 0x80200000 |
FDT ở chế độ BIOS | 0x80000000 |
Cơ sở bộ nhớ vật lý | 0x80000000 |
chương trình cơ sở pVM | 0x7FE00000 |
Bộ nhớ thiết bị | 0x10000 - 0x40000000 |
Bộ nhớ vật lý được phân bổ bằng mmap
và bộ nhớ được tặng cho VM để điền vào các vùng bộ nhớ của nó, được gọi là memslots , với KVM_SET_USER_MEMORY_REGION
ioctl. Do đó, tất cả bộ nhớ pVM khách được gán cho phiên bản crosvm quản lý nó và có thể dẫn đến quá trình bị hủy (chấm dứt VM) nếu máy chủ bắt đầu hết bộ nhớ trống. Khi một máy ảo bị dừng, bộ nhớ sẽ tự động bị xóa bởi trình ảo hóa và được trả về nhân máy chủ.
Trong KVM thông thường, VMM giữ lại quyền truy cập vào tất cả bộ nhớ khách. Với pKVM, bộ nhớ khách không được ánh xạ khỏi không gian địa chỉ vật lý của máy chủ khi nó được tặng cho khách. Ngoại lệ duy nhất là bộ nhớ được khách chia sẻ lại một cách rõ ràng, chẳng hạn như đối với các thiết bị virtio.
Các vùng MMIO trong không gian địa chỉ của khách không được ánh xạ. Quyền truy cập vào các vùng này của khách bị mắc kẹt và dẫn đến một sự kiện I/O trên VM FD. Cơ chế này được sử dụng để triển khai các thiết bị ảo. Ở chế độ được bảo vệ, khách phải xác nhận rằng một vùng trong không gian địa chỉ của nó được sử dụng cho MMIO bằng cách sử dụng siêu cuộc gọi, để giảm nguy cơ rò rỉ thông tin ngoài ý muốn.
lập kế hoạch
Mỗi CPU ảo được đại diện bởi một luồng POSIX và được lên lịch bởi bộ lập lịch Linux máy chủ. Chuỗi gọi KVM_RUN
ioctl trên vCPU FD, dẫn đến việc trình ảo hóa chuyển sang bối cảnh vCPU khách. Bộ lập lịch máy chủ tính thời gian dành cho ngữ cảnh khách như thời gian được sử dụng bởi luồng vCPU tương ứng. KVM_RUN
trả về khi có một sự kiện phải được xử lý bởi VMM, chẳng hạn như I/O, kết thúc ngắt hoặc vCPU tạm dừng. VMM xử lý sự kiện và gọi lại KVM_RUN
.
Trong thời gian KVM_RUN
, bộ lập lịch lưu trữ vẫn có thể ưu tiên luồng, ngoại trừ việc thực thi mã trình ảo hóa EL2, mã này không được ưu tiên. Bản thân pVM khách không có cơ chế kiểm soát hành vi này.
Bởi vì tất cả các luồng vCPU được lên lịch giống như bất kỳ tác vụ không gian người dùng nào khác, nên chúng tuân theo tất cả các cơ chế QoS tiêu chuẩn. Cụ thể, mỗi luồng vCPU có thể được liên kết với các CPU vật lý, được đặt trong các bộ cpus, được tăng cường hoặc giới hạn bằng cách sử dụng kẹp sử dụng, thay đổi chính sách ưu tiên/lập lịch của chúng, v.v.
thiết bị ảo
crosvm hỗ trợ một số thiết bị, bao gồm:
- virtio-blk cho hình ảnh đĩa tổng hợp, chỉ đọc hoặc đọc-ghi
- vhost-vsock để liên lạc với máy chủ
- virtio-pci như vận chuyển virtio
- pl030 đồng hồ thời gian thực (RTC)
- 16550a UART cho giao tiếp nối tiếp
chương trình cơ sở pVM
Phần sụn pVM (pvmfw) là mã đầu tiên được thực thi bởi pVM, tương tự như ROM khởi động của thiết bị vật lý. Mục tiêu chính của pvmfw là khởi động khởi động an toàn và lấy được bí mật duy nhất của pVM. pvmfw không bị giới hạn sử dụng với bất kỳ HĐH cụ thể nào, chẳng hạn như Microdroid , miễn là HĐH được crosvm hỗ trợ và đã được ký hợp lệ.
Tệp nhị phân pvmfw được lưu trữ trong phân vùng flash có cùng tên và được cập nhật bằng OTA .
khởi động thiết bị
Trình tự các bước sau đây được thêm vào quy trình khởi động của thiết bị hỗ trợ pKVM:
- Bộ tải khởi động Android (ABL) tải pvmfw từ phân vùng của nó vào bộ nhớ và xác minh hình ảnh.
- ABL có được các bí mật của Công cụ tạo thành phần nhận dạng thiết bị (DICE) (Số nhận dạng thiết bị tổng hợp (CDIs) và Chuỗi chứng chỉ khởi động (BCC)) từ Nguồn gốc đáng tin cậy.
- ABL thực hiện đo lường và tạo DICE từ bí mật của pvmfw (CDIs) và nối chúng vào tệp nhị phân pvmfw.
- ABL thêm nút vùng bộ nhớ dành riêng cho
linux,pkvm-guest-firmware-memory
vào DT, mô tả vị trí và kích thước của tệp nhị phân pvmfw và các bí mật mà nó thu được trong bước trước. - ABL trao quyền kiểm soát cho Linux và Linux khởi tạo pKVM.
- pKVM hủy ánh xạ vùng bộ nhớ pvmfw khỏi các bảng trang giai đoạn 2 của máy chủ và bảo vệ nó khỏi máy chủ (và khách) trong suốt thời gian hoạt động của thiết bị.
Sau khi khởi động thiết bị, Microdroid được khởi động theo các bước trong phần Trình tự khởi động của tài liệu Microdroid .
khởi động pVM
Khi tạo một pVM, crosvm (hoặc một VMM khác) phải tạo một khe ghi nhớ đủ lớn để trình ảo hóa phổ biến hình ảnh pvmfw. VMM cũng bị hạn chế trong danh sách các thanh ghi có giá trị ban đầu mà nó có thể đặt (x0-x14 cho vCPU chính, không có giá trị nào cho vCPU phụ). Các thanh ghi còn lại được dành riêng và là một phần của ABI hypanneror-pvmfw.
Khi chạy pVM, trước tiên trình ảo hóa sẽ trao quyền điều khiển vCPU chính cho pvmfw. Phần sụn hy vọng crosvm đã tải nhân có chữ ký AVB, có thể là bộ tải khởi động hoặc bất kỳ hình ảnh nào khác và một FDT chưa được ký vào bộ nhớ ở các độ lệch đã biết. pvmfw xác thực chữ ký AVB và nếu thành công, sẽ tạo cây thiết bị đáng tin cậy từ FDT đã nhận, xóa bí mật của nó khỏi bộ nhớ và phân nhánh tới điểm vào của tải trọng. Nếu một trong các bước xác minh không thành công, chương trình cơ sở sẽ đưa ra siêu lệnh PSCI SYSTEM_RESET
.
Giữa các lần khởi động, thông tin về phiên bản pVM được lưu trữ trong một phân vùng (thiết bị virtio-blk) và được mã hóa bằng bí mật của pvmfw để đảm bảo rằng, sau khi khởi động lại, bí mật sẽ được cung cấp cho đúng phiên bản.