2022-07-01 10:11:18 +02:00
|
|
|
//
|
|
|
|
|
// Copyright © 2022 osy. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
import Virtualization
|
|
|
|
|
|
|
|
|
|
/// Basic hardware settings.
|
|
|
|
|
@available(iOS, unavailable, message: "Apple Virtualization not available on iOS")
|
|
|
|
|
@available(macOS 11, *)
|
|
|
|
|
struct UTMAppleConfigurationSystem: Codable {
|
2022-07-03 21:26:26 +02:00
|
|
|
private let bytesInMib = UInt64(1048576)
|
|
|
|
|
|
2022-07-10 20:37:50 -07:00
|
|
|
static var currentArchitecture: String {
|
|
|
|
|
#if arch(arm64)
|
|
|
|
|
"aarch64"
|
|
|
|
|
#elseif arch(x86_64)
|
|
|
|
|
"x86_64"
|
|
|
|
|
#else
|
|
|
|
|
#error("Unsupported architecture.")
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var architecture: String = Self.currentArchitecture
|
|
|
|
|
|
2022-07-01 10:11:18 +02:00
|
|
|
/// Number of CPU cores to emulate. Set to 0 to match the number of available cores on the host.
|
|
|
|
|
var cpuCount: Int = 0
|
|
|
|
|
|
|
|
|
|
/// The RAM of the guest in MiB.
|
|
|
|
|
var memorySize: Int = 4096
|
|
|
|
|
|
2022-09-17 23:28:49 +03:00
|
|
|
var boot: UTMAppleConfigurationBoot = try! .init(for: .none)
|
2022-07-01 10:11:18 +02:00
|
|
|
|
|
|
|
|
var macPlatform: UTMAppleConfigurationMacPlatform?
|
|
|
|
|
|
2022-08-03 16:01:02 -07:00
|
|
|
var genericPlatform: UTMAppleConfigurationGenericPlatform?
|
|
|
|
|
|
2022-07-01 10:11:18 +02:00
|
|
|
enum CodingKeys: String, CodingKey {
|
2022-07-10 20:37:50 -07:00
|
|
|
case architecture = "Architecture"
|
2022-07-01 10:11:18 +02:00
|
|
|
case cpuCount = "CPUCount"
|
|
|
|
|
case memorySize = "MemorySize"
|
|
|
|
|
case boot = "Boot"
|
|
|
|
|
case macPlatform = "MacPlatform"
|
2022-08-03 16:01:02 -07:00
|
|
|
case genericPlatform = "GenericPlatform"
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init(from decoder: Decoder) throws {
|
|
|
|
|
let values = try decoder.container(keyedBy: CodingKeys.self)
|
2022-07-10 20:37:50 -07:00
|
|
|
architecture = try values.decode(String.self, forKey: .architecture)
|
2022-07-01 10:11:18 +02:00
|
|
|
cpuCount = try values.decode(Int.self, forKey: .cpuCount)
|
|
|
|
|
memorySize = try values.decode(Int.self, forKey: .memorySize)
|
|
|
|
|
boot = try values.decode(UTMAppleConfigurationBoot.self, forKey: .boot)
|
|
|
|
|
macPlatform = try values.decodeIfPresent(UTMAppleConfigurationMacPlatform.self, forKey: .macPlatform)
|
2022-08-03 16:01:02 -07:00
|
|
|
genericPlatform = try values.decodeIfPresent(UTMAppleConfigurationGenericPlatform.self, forKey: .genericPlatform)
|
2024-11-20 10:41:42 -08:00
|
|
|
if boot.operatingSystem == .linux && genericPlatform == nil {
|
|
|
|
|
// fix a bug where this was not created
|
|
|
|
|
genericPlatform = UTMAppleConfigurationGenericPlatform()
|
|
|
|
|
}
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
|
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
2022-07-10 20:37:50 -07:00
|
|
|
try container.encode(architecture, forKey: .architecture)
|
2022-07-01 10:11:18 +02:00
|
|
|
try container.encode(cpuCount, forKey: .cpuCount)
|
|
|
|
|
try container.encode(memorySize, forKey: .memorySize)
|
|
|
|
|
try container.encode(boot, forKey: .boot)
|
|
|
|
|
if boot.operatingSystem == .macOS {
|
|
|
|
|
try container.encodeIfPresent(macPlatform, forKey: .macPlatform)
|
2022-08-03 16:01:02 -07:00
|
|
|
} else if boot.operatingSystem == .linux {
|
|
|
|
|
try container.encodeIfPresent(genericPlatform, forKey: .genericPlatform)
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Conversion of old config format
|
|
|
|
|
|
|
|
|
|
@available(iOS, unavailable, message: "Apple Virtualization not available on iOS")
|
|
|
|
|
@available(macOS 11, *)
|
|
|
|
|
extension UTMAppleConfigurationSystem {
|
|
|
|
|
init(migrating oldConfig: UTMLegacyAppleConfiguration) {
|
|
|
|
|
self.init()
|
|
|
|
|
cpuCount = oldConfig.cpuCount
|
2022-07-03 21:26:26 +02:00
|
|
|
memorySize = Int(oldConfig.memorySize / bytesInMib)
|
2022-07-01 10:11:18 +02:00
|
|
|
if let oldBoot = oldConfig.bootLoader {
|
|
|
|
|
boot = UTMAppleConfigurationBoot(migrating: oldBoot)
|
|
|
|
|
}
|
|
|
|
|
#if arch(arm64)
|
|
|
|
|
if #available(macOS 12, *) {
|
|
|
|
|
if let oldPlatform = oldConfig.macPlatform {
|
|
|
|
|
macPlatform = UTMAppleConfigurationMacPlatform(migrating: oldPlatform)
|
|
|
|
|
}
|
2022-08-03 16:02:06 -07:00
|
|
|
boot.macRecoveryIpswURL = oldConfig.macRecoveryIpswURL
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
2022-09-17 23:11:17 +03:00
|
|
|
if boot.operatingSystem == .linux {
|
|
|
|
|
genericPlatform = UTMAppleConfigurationGenericPlatform()
|
|
|
|
|
}
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Creating Apple config
|
|
|
|
|
|
|
|
|
|
@available(iOS, unavailable, message: "Apple Virtualization not available on iOS")
|
|
|
|
|
@available(macOS 11, *)
|
|
|
|
|
extension UTMAppleConfigurationSystem {
|
2022-09-17 23:10:53 +03:00
|
|
|
func fillVZConfiguration(_ vzconfig: VZVirtualMachineConfiguration) throws {
|
2022-07-10 20:38:48 -07:00
|
|
|
if cpuCount > 0 {
|
|
|
|
|
vzconfig.cpuCount = cpuCount
|
|
|
|
|
} else {
|
|
|
|
|
let hostPcorePhysicalCpu = Int(Self.sysctlIntRead("hw.perflevel0.physicalcpu"))
|
|
|
|
|
let hostPhysicalCpu = Int(Self.sysctlIntRead("hw.physicalcpu"))
|
|
|
|
|
vzconfig.cpuCount = hostPcorePhysicalCpu > 0 ? hostPcorePhysicalCpu : hostPhysicalCpu
|
|
|
|
|
}
|
2022-07-03 21:26:26 +02:00
|
|
|
vzconfig.memorySize = UInt64(memorySize) * bytesInMib
|
2022-07-01 10:11:18 +02:00
|
|
|
vzconfig.bootLoader = boot.vzBootloader()
|
2022-09-17 23:10:53 +03:00
|
|
|
if boot.operatingSystem == .macOS {
|
|
|
|
|
#if arch(arm64)
|
|
|
|
|
if #available(macOS 12, *),
|
|
|
|
|
let macPlatform = macPlatform,
|
|
|
|
|
let platform = macPlatform.vzMacPlatform() {
|
2022-07-01 10:11:18 +02:00
|
|
|
vzconfig.platform = platform
|
2022-09-17 23:10:53 +03:00
|
|
|
} else {
|
|
|
|
|
throw UTMAppleConfigurationError.platformUnsupported
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
2022-09-17 23:10:53 +03:00
|
|
|
#else
|
|
|
|
|
throw UTMAppleConfigurationError.platformUnsupported
|
|
|
|
|
#endif
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
2022-09-17 23:10:53 +03:00
|
|
|
if #available(macOS 12, *),
|
|
|
|
|
let genericPlatform = genericPlatform,
|
|
|
|
|
let platform = genericPlatform.vzGenericPlatform() {
|
|
|
|
|
vzconfig.platform = platform
|
2022-08-03 16:01:02 -07:00
|
|
|
}
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|
2022-07-10 20:38:48 -07:00
|
|
|
|
|
|
|
|
private static func sysctlIntRead(_ name: String) -> UInt64 {
|
|
|
|
|
var value: UInt64 = 0
|
|
|
|
|
var size = MemoryLayout<UInt64>.size
|
|
|
|
|
sysctlbyname(name, &value, &size, nil, 0)
|
|
|
|
|
return value
|
|
|
|
|
}
|
2022-07-01 10:11:18 +02:00
|
|
|
}
|