Apple Silicon và máy ảo: Vượt qua giới hạn 2 VM (2023)
Apple Silicon and Virtual Machines: Beating the 2 VM Limit (2023)
macOS Internals Tìm hiểu sâu Xây dựng Bộ sưu tập hạt nhân phát triển Định cấu hình máy Mac của chúng tôi để khởi động Bộ sưu tập hạt nhân phát triển Đưa máy của chúng tôi hoạt động! Apple đã ban ơn cho chúng ta tính năng này từ khi nào? Hoàn tác công việc của chúng tôi về cập nhật hệ điều hành
- Tìm hiểu sâu về nội bộ macOS
- Xây dựng bộ sưu tập hạt nhân phát triển
- Định cấu hình máy Mac của chúng tôi để khởi động Bộ sưu tập hạt nhân phát triển
- Đưa máy của chúng tôi hoạt động!
- Apple đã ban ơn cho chúng ta điều này từ khi nào tính năng?
- Đang hoàn tác công việc của chúng tôi đối với các bản cập nhật hệ điều hành
- Suy nghĩ kết thúc
Đối với những ai đang thắc mắc tôi đã làm gì trong vài tháng qua ngoài OpenCore Legacy Patcher, tôi đã có được cơ hội tuyệt vời để làm việc với tư cách là Thực tập sinh quản trị viên Mac tại một công ty tư vấn địa phương.
Một trong những lĩnh vực tôi đã từng đến hoạt động khá nhiều với Máy ảo macOS, cụ thể là Máy ảo Apple Silicon dựa trên Khung ảo hóa của Apple. Tuy nhiên, không lâu sau khi thực hiện nhiều hoạt động phát triển và thử nghiệm bằng cách sử dụng ngăn xếp máy ảo của Apple (thông qua dự án tuyệt vời, UTM), tôi nhận thấy một hạn chế rất khó chịu: Máy chủ Apple Silicon chỉ có thể có tối đa 2 máy ảo khách macOS hoạt động cùng một lúc.
Điều này thường thấy nhất với lỗi này, được tạo bởi Virtualization.framework:
Số lượng máy ảo vượt quá giới hạn. Đã đạt đến số lượng máy ảo hoạt động được hỗ trợ tối đa.

Lý do chính gây ra lỗi này xuất phát từ SLA của macOS, phần 2.B.iii:
(iii) để cài đặt, sử dụng và chạy tối đa hai (2) bản sao hoặc phiên bản bổ sung của Phần mềm Apple hoặc bất kỳ phần mềm hệ điều hành macOS hoặc OS X nào trước đây hoặc bản phát hành tiếp theo của Phần mềm Apple, trong môi trường hệ điều hành ảo trên mỗi máy tính mang nhãn hiệu Apple mà bạn sở hữu hoặc kiểm soát đang chạy Phần mềm Apple, nhằm mục đích: (a) phát triển phần mềm; (b) thử nghiệm trong quá trình phát triển phần mềm; (c) sử dụng Máy chủ macOS; hoặc (d) sử dụng cá nhân, phi thương mại.
Mặc dù tôi không thể chính thức ảo hóa nhiều hơn 2 bản sao macOS trên một máy cùng một lúc để phục vụ công việc, nhưng tôi vẫn muốn tìm hiểu xem Apple nhúng những bước kiểm tra này vào đâu trong macOS và liệu những người có sở thích và nhà nghiên cứu có thể kích hoạt hỗ trợ cho nhiều hơn 2 máy ảo macOS đang hoạt động cùng một lúc hay không.
Nội bộ macOS Lặn sâu
Để bắt đầu, ban đầu tôi nghĩ giới hạn này là dựa trên không gian người dùng và như vậy sẽ được nhúng ở đâu đó trong /System/Library/Frameworks/Virtualization.framework. Do sự hợp nhất các khung của macOS Big Sur, chúng tôi sẽ cần trích xuất khung theo cách thủ công hoặc sử dụng công cụ như Hopper Disassembler để tải các tệp nhị phân cụ thể được nhúng trong bộ đệm chia sẻ dyld.
- Thông tin thêm về macOS Framework và bộ đệm chia sẻ dyld: Trận chiến chống lại các tệp nhị phân trên đĩa
Với điều này, tôi đã có thể kiểm tra khuôn khổ chặt chẽ hơn. Tuy nhiên, sau nhiều giờ nghiên cứu, tôi không thể tìm ra nơi Apple áp đặt giới hạn VM. Tốt nhất, tôi chỉ có thể xác định rằng thông báo lỗi được tạo từ khung nhưng không nơi nào trong không gian người dùng Apple xác định giới hạn 2 VM được mã hóa cứng…
Sau mẹo từ jevinskie trên máy chủ Hack Different Discord, tôi được biết rằng giới hạn khách của Apple được triển khai ở đâu đó trong phần nguồn đóng của XNU (nhân macOS). Mặc dù tôi không có bất kỳ chuỗi nào để giải quyết nhưng tôi biết rằng Hạt nhân Intel sẽ không có cùng mã. Vì vậy, bằng một phép so sánh không nhanh giữa các chức năng và chuỗi của nhân Intel và Apple Silicon, tôi nhận thấy rằng ngăn xếp VM chính nằm dưới hv_vm_*.
Đưa hạt nhân phát triển cho macOS Sonoma Beta 4 (23A5301h) vào IDA, tôi đã tìm thấy mã init cho ngăn xếp VM: hv_init():
- Để có được hạt nhân phát triển, bạn cần phải tải xuống Bộ công cụ gỡ lỗi hạt nhân của hệ điều hành của bạn khỏi cổng thông tin dành cho nhà phát triển

Ở đây chúng ta thấy cách Apple xử lý giới hạn VM: Sử dụng biến int hv_apple_isa_vm_quota, kernel sẽ giảm/tăng biến như Máy ảo mới khi bắt đầu/dừng:
| Tăng dần Chức năng | Hàm giảm dần |
|---|---|
void hv_vm_destroy_0(hv_vm_t_0 *vm) |
void hv_trap_vm_create(uint64_t_0 arg) |
![]() |
![]() |
Và một điều thú vị khác, 2 đối số khởi động mới: hypervisor= và hv_apple_isa_vm_quota=.
Cái trước là một bước kiểm tra cổng đơn giản cho cái sau, điều này thú vị hơn nhiều: hv_apple_isa_vm_quota= có thể ghi đè giới hạn VM trong kernel!
Tuy nhiên, sau khi nghiên cứu thêm, tôi thấy rằng logic này là không giống nhau trong hạt nhân phát hành. Thay vào đó, Apple đã hoán đổi boot-arg hypervisor bằng kiểm tra AppleInternal thông qua Bảo vệ tính toàn vẹn hệ thống:
- Để biết thêm một chút thông tin về SIP, tôi đã viết về điều đó ở đây: Bảo vệ tính toàn vẹn của hệ thống: Cài đặt bị hiểu lầm
/* CSR_ALLOW_APPLE_INTERNAL = 0x10
Từ nguồn XNU:
#define CSR_ALLOW_APPLE_INTERNAL (1 << 4)
https://opensource.apple.com/source/xnu/xnu-7195.121.3/bsd/sys/csr.h.auto.html
*/
if ((*(int8_t *)_csr_config & 0x10) != 0x0) {
_PE_parse_boot_argn_internal(*0xfffffe00072696d0 + 0x6c, "hv_apple_isa_vm_quota", 0xfffffe0007b58410, 0x4, 0x0);
Ở đây chúng tôi có 2 tùy chọn:
- Khởi động hạt nhân phát triển của Apple
- Sửa đổi hạt nhân phát hành để loại bỏ
AppleInternalkiểm tra
Để tiết kiệm chút tỉnh táo còn lại, chúng ta sẽ sử dụng tùy chọn đầu tiên. Vì vậy, bây giờ thử thách tiếp theo của tôi: Khởi động nhân phát triển trên MacBook Pro của tôi.
Xây dựng bộ sưu tập hạt nhân phát triển
Để xây dựng bộ sưu tập hạt nhân phát triển, chúng tôi cần tìm nạp Bộ gỡ lỗi hạt nhân thích hợp từ Trang web dành cho nhà phát triển của Apple. Lưu ý rằng KDK phải khớp với máy chủ, nếu không, sự cố có thể xảy ra cả trong quá trình liên kết kernel và kext cũng như trong khi khởi động.
Sau khi bạn đã tải xuống và cài đặt gói nhúng KDK Disk Image, tiếp theo hãy kiểm tra loại hạt nhân máy Mac của bạn công dụng:
uname -v | awk -F '/' '{print $NF}'| awk -F '_' '{print $NF}'
Trên MacBook Pro M2 Pro (Mac14,9), thao tác này sẽ trả về T6020. Trên các mẫu CPU khác, đặc biệt là các thế hệ khác nhau như M1 vs M2, biến thể kernel sẽ khác:

Bây giờ chúng ta có thể bắt đầu xây dựng hạt nhân của mình!
Lời gọi sau đây giả định:
- Máy chủ sử dụng hạt nhân
T6020 - Máy chủ đang chạy macOS 14.0, Build 23A5301h
Đảm bảo bạn điều chỉnh lệnh gọi bên dưới để phù hợp với máy chủ của mình một cách tương ứng.
- Rất đánh giá cao các kỹ sư tại Apple, đặc biệt là Jeremy C. Andrus vì bài đăng trên blog của họ về cách khởi động hạt nhân tùy chỉnh:
sudo kmutil tạo \
--arch arm64e \
--không được phép \
--phát triển hậu tố biến thể \
--khởi động mới \
--boot-path VirtualMachine.kc \
--hạt nhân /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Kernels/kernel.development.t6020 \
--repository /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Extensions \
--repository /System/Library/Extensions \
--repository /System/Library/DriverExtensions \
--explicit-only $(kmutil kiểm tra -V phát hành --no-header | grep -v "SEPHiber" | awk '{print " -b "$1; }')
Điều này sẽ tạo ra VirtualMachine.kc trong thư mục chính của bạn. Hãy ghi nhớ đường dẫn vì chúng ta sẽ cần truy cập vào đường dẫn này từ recoveryOS.
Định cấu hình máy Mac của chúng tôi để khởi động Bộ sưu tập hạt nhân phát triển
Cuối cùng, tắt máy Mac của bạn và khởi động vào recovery bằng cách giữ nút nguồn và chọn “Tùy chọn”:
Tiếp theo, ủy quyền cho người dùng và chọn Tiện ích -> Terminal từ Thanh menu. Ở đây chúng tôi sẽ đặt một số chính sách cho máy của mình:
- Tắt tính năng Bảo vệ tính toàn vẹn của hệ thống
- Cho phép truyền đối số khởi động tùy chỉnh
- Định cấu hình máy Mac của chúng tôi để khởi động Bộ sưu tập hạt nhân tùy chỉnh của chúng tôi (điều chỉnh
Macintosh HDtheo âm lượng của bạn) - Đặt đối số khởi động của chúng tôi
kcsuffix=: Đặt Bộ sưu tập hạt nhân biến thể để khởi độnghypervisor=: Kích hoạt các tính năng đặc biệt trong Ngăn xếp ảo hóa (cụ thể là ghi đè hạn ngạch VM)hv_apple_isa_vm_quota=: Ghi đè hạn ngạch VM, giá trị tối đa là0x7FFFFFFF(được đặt thành0xFF(255) VM cho tính thực tế)
tắt csrutil
bputil --disable-boot-args-restriction
kmutil configure-boot --volume /Volumes/Macintosh\ HD --custom-boot-object /Volumes/Macintosh\ HD/Users/*/VirtualMachine.kc
nvram 40A0DDD2-77F8-4392-B4A3-1E7304206516:boot-args='kcsuffix=trình ảo hóa phát triển=0x1 hv_apple_isa_vm_quota=0xFF'
Sau khi khởi động lại, bạn có thể xác minh điều này được áp dụng trong Thiết bị đầu cuối:
sysctl kern.osbuildconfig
nvram boot-args

Đưa máy của chúng tôi hoạt động!
Bây giờ mọi thứ đã sẵn sàng, bạn sẽ muốn sử dụng bất kỳ giải pháp ảo hóa nào bằng cách sử dụng Virtualization.framework. Một số ví dụ bao gồm:
Bây giờ chúng ta có thể kích hoạt máy ảo của mình! Bên dưới, tôi có 9 máy ảo macOS chạy cùng lúc trên MacBook Pro M2 Pro của mình và vẫn có thể sử dụng được để thử nghiệm!

(Đây cũng là lần đầu tiên tôi nghe nói quạt bật chiếc máy này nên chúng tôi biết mình đang kiếm được nhiều tiền ;p)
Apple đã ban ân cho chúng ta tính năng này khi nào?
Có vẻ như với macOS 12, Monterey, Apple đã thêm boot-arg này cùng với ngăn ảo hóa. Và như chúng ta đã thấy với nhân của Sonoma, kiểm tra AppleInternal vẫn hiện diện ngay cả ở Monterey. Có vẻ như Apple vẫn còn rất nhiều bí mật ẩn giấu trong XNU.

Đang hoàn tác công việc của chúng tôi đối với các bản cập nhật hệ điều hành
Khi sử dụng bộ sưu tập hạt nhân tùy chỉnh với Apple Silicon, có một số nhược điểm đáng tiếc. Vấn đề lớn nhất là các bản cập nhật hệ điều hành được sắp xếp hợp lý không còn khả dụng nữa. Bạn vẫn có thể cài đặt các bản cập nhật, tuy nhiên sau khi hoàn tất cập nhật, máy của bạn sẽ báo lỗi.
Để khắc phục sự cố này, bạn cần hoàn nguyên về bộ sưu tập kernel gốc trên máy của mình.
Để đặt lại, bạn chỉ cần tạo Chính sách khởi động mới với bputil trong recoveryOS. Điều này có thể có bảo mật hoàn toàn (--bảo mật đầy đủ) hoặc bất kỳ kết hợp nào khác (ví dụ: --vô hiệu hóa hạn chế khởi động-args). Khi bạn chạy cái này trong recoveryOS và khởi động lại, kernel gốc sẽ có hiệu lực.
Suy nghĩ kết thúc
Nhìn chung đây là một hành trình nghiên cứu thực sự thú vị và tôi rất vui vì đã có thể tìm ra cách Apple thực hiện hạn chế này. Ngoài ra, tôi thực sự đánh giá cao rằng mặc dù đây là trường hợp sử dụng không được hỗ trợ, nhưng nhóm Ảo hóa trong CoreOS vẫn cung cấp tùy chọn cho những người đam mê ghi đè giới hạn này (ngay cả khi không được ghi chép lại hoặc cách thực hiện đơn giản).
Tôi dự định thực hiện một số cải tiến trong tương lai (mặc dù khó có thể triển khai):
- Phát triển công cụ để tự động hóa quá trình xây dựng và khởi động KC.
- Tải xuống và tạo bộ sưu tập hạt nhân phát triển cho một máy chủ nhất định.
- Định cấu hình máy chủ trong recoveryOS để khởi động bộ sưu tập kernel.
- Xem xét việc phát triển tiện ích mở rộng hạt nhân có thể ghi đè biến
hv_apple_isa_vm_quota.- Loại bỏ nhu cầu về hạt nhân phát triển, tùy chỉnh bộ sưu tập.
Nếu không, tôi hy vọng cộng đồng thấy bài đăng blog này thú vị, hành trình tiếp theo của tôi có thể sẽ là xem liệu Ghi đè số sê-ri/Đăng ký DEP cho máy ảo Apple Silicon có khả thi hay không. Dù có thể không may mắn như bài viết này ;p
Tác giả: krackers

