Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux support #152

Merged
merged 3 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ VirtualBuddy can virtualize macOS 12 and later on Apple Silicon, with the goal o
- **Apple Silicon Mac**
- macOS 12.3 or later
- In order to install a version of macOS that's newer than the version running on the host (for example, macOS 13 VM in VirtualBuddy running on macOS 12), Xcode is required; Xcode beta may be required for installing macOS betas (`FB11061314`)
- In order to install a Linux distro, macOS 13 is required

⚠️ WARNING: This project is experimental. Things might break or not work as expected.

Expand All @@ -17,11 +18,15 @@ VirtualBuddy can virtualize macOS 12 and later on Apple Silicon, with the goal o
### Feature Checklist

- [x] Ability to boot any version of macOS 12 or macOS 13, including betas
- [x] Ability to boot some ARM-based Linux distros (tested with Ubuntu Server and Ubuntu Desktop)
- [x] Built-in installation wizard
- [x] Select from a collection of restore images available on Apple's servers
- [x] Install the latest stable version of macOS
- [x] Local restore image IPSW file
- [x] Custom restore image URL
- [x] Install a Linux distro from a local .iso file
- [ ] Select from a collection of Linux distros
- [ ] Install Linux from URL
- [x] Boot into recovery mode (in order to disable SIP, for example)
- [x] Networking and file sharing support
- [x] Clipboard sharing (without the need to be running macOS Ventura) (experimental ¹)
Expand Down
8 changes: 8 additions & 0 deletions VirtualBuddy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
0196B45329292B2A00614EF1 /* LinuxVirtualMachineConfigurationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0196B45229292B2A00614EF1 /* LinuxVirtualMachineConfigurationHelper.swift */; };
4BA6BE7D293D22E500F396AE /* VirtualMachineConfigurationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA6BE7C293D22E500F396AE /* VirtualMachineConfigurationHelper.swift */; };
F417255B2884D79C004FF8A7 /* FixSwiftUIMaterialInPreviews.m in Sources */ = {isa = PBXBuildFile; fileRef = F417255A2884D79C004FF8A7 /* FixSwiftUIMaterialInPreviews.m */; };
F417255D288604A8004FF8A7 /* SoundConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F417255C288604A8004FF8A7 /* SoundConfigurationView.swift */; };
F417255F28861604004FF8A7 /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = F417255E28861604004FF8A7 /* DecodableDefault.swift */; };
Expand Down Expand Up @@ -191,6 +193,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
0196B45229292B2A00614EF1 /* LinuxVirtualMachineConfigurationHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinuxVirtualMachineConfigurationHelper.swift; sourceTree = "<group>"; };
4BA6BE7C293D22E500F396AE /* VirtualMachineConfigurationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VirtualMachineConfigurationHelper.swift; sourceTree = "<group>"; };
F417255A2884D79C004FF8A7 /* FixSwiftUIMaterialInPreviews.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FixSwiftUIMaterialInPreviews.m; sourceTree = "<group>"; };
F417255C288604A8004FF8A7 /* SoundConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundConfigurationView.swift; sourceTree = "<group>"; };
F417255E28861604004FF8A7 /* DecodableDefault.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -647,7 +651,9 @@
F4A21BF028032FBD001072B8 /* Helpers */ = {
isa = PBXGroup;
children = (
4BA6BE7C293D22E500F396AE /* VirtualMachineConfigurationHelper.swift */,
F4BE9C7527FF055100B648F8 /* MacOSVirtualMachineConfigurationHelper.swift */,
0196B45229292B2A00614EF1 /* LinuxVirtualMachineConfigurationHelper.swift */,
F46FFBA92804F0A000D61023 /* VZVirtualMachineConfiguration+NVRAM.swift */,
F47FFA56280633F000BD1F87 /* VMScreenshotter.swift */,
F417257028877121004FF8A7 /* DiskImageGenerator.swift */,
Expand Down Expand Up @@ -1192,6 +1198,7 @@
F4A21BF428033102001072B8 /* VBError.swift in Sources */,
F4D0F71F2867517A004D5782 /* AppUpdateChannel.swift in Sources */,
F46FFBA62804E81E00D61023 /* VBObjCHookingPoint.m in Sources */,
4BA6BE7D293D22E500F396AE /* VirtualMachineConfigurationHelper.swift in Sources */,
F48E0D0728885E140080DDFA /* PreviewSupport.swift in Sources */,
F46FFBAA2804F0A000D61023 /* VZVirtualMachineConfiguration+NVRAM.swift in Sources */,
F4C189F72848F6A600335EC7 /* VirtualCoreConstants.swift in Sources */,
Expand All @@ -1211,6 +1218,7 @@
F4BE9C7827FF055100B648F8 /* MacOSVirtualMachineConfigurationHelper.swift in Sources */,
F46FFBAC28059FF600D61023 /* VMInstance.swift in Sources */,
F465C3B0284F9660006E9ED4 /* VBRestoreImagesResponse.swift in Sources */,
0196B45329292B2A00614EF1 /* LinuxVirtualMachineConfigurationHelper.swift in Sources */,
F465C3B2284F9666006E9ED4 /* VBRestoreImageInfo.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ public struct VBMacConfiguration: Hashable, Codable {
case unsupported([String])
}

public enum SystemType: String, Codable, CaseIterable {
case mac
case linux
}

public static let currentVersion = 0
@DecodableDefault.Zero public var version = VBMacConfiguration.currentVersion

@DecodableDefault.FirstCase
public var systemType: SystemType = .mac

public var hardware = VBMacDevice.default
public var sharedFolders = [VBSharedFolder]()
@DecodableDefault.False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public extension DecodableDefault {
typealias Source = DecodableDefaultSource
typealias List = Decodable & ExpressibleByArrayLiteral
typealias Map = Decodable & ExpressibleByDictionaryLiteral
typealias Enum = Decodable & CaseIterable

enum Sources {
public enum Zero: Source {
Expand Down Expand Up @@ -70,6 +71,10 @@ public extension DecodableDefault {
public enum EmptyPlaceholder<T: ProvidesEmptyPlaceholder>: Source {
public static var defaultValue: T { .empty }
}

public enum FirstCase<T: Enum>: Source {
public static var defaultValue: T { T.allCases.first! }
}
}
}

Expand All @@ -81,6 +86,7 @@ public extension DecodableDefault {
typealias EmptyList<T: List> = Wrapper<Sources.EmptyList<T>>
typealias EmptyMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
typealias EmptyPlaceholder<T: ProvidesEmptyPlaceholder> = Wrapper<Sources.EmptyPlaceholder<T>>
typealias FirstCase<T: Enum> = Wrapper<Sources.FirstCase<T>>
}

extension DecodableDefault.Wrapper: Equatable where Value: Equatable {}
Expand Down
11 changes: 11 additions & 0 deletions VirtualCore/Source/Models/VBVirtualMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public struct VBVirtualMachine: Identifiable {
public var installFinished: Bool = false
public var firstBootDate: Date? = nil
public var lastBootDate: Date? = nil
public var installImageURL: URL? = nil
}

public var id: String { bundleURL.absoluteString }
Expand Down Expand Up @@ -151,6 +152,16 @@ public extension VBVirtualMachine {
try saveMetadata()
}

@available(macOS 13, *)
init(creatingAtURL bundleURL: URL, linuxInstallerURL: URL) throws {
guard !FileManager.default.fileExists(atPath: bundleURL.path) else { fatalError() }
try FileManager.default.createDirectory(at: bundleURL, withIntermediateDirectories: true)
self.bundleURL = bundleURL
self.configuration = .init(systemType: .linux)
self.metadata = Metadata(installFinished: false, firstBootDate: .now, lastBootDate: .now, installImageURL: linuxInstallerURL)
try saveMetadata()
}

func saveMetadata() throws {
#if DEBUG
guard !ProcessInfo.isSwiftUIPreview else { return }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
See LICENSE folder for this sample’s licensing information.

Abstract:
Helper that creates various configuration objects exposed in the `VZVirtualMachineConfiguration`.
*/

import Foundation
import Virtualization

@available(macOS 13.0, *)
struct LinuxVirtualMachineConfigurationHelper: VirtualMachineConfigurationHelper {
let vm: VBVirtualMachine

func createInstallDevice(installImageURL: URL) throws -> VZStorageDeviceConfiguration {
let attachment = try VZDiskImageStorageDeviceAttachment(url: installImageURL, readOnly: true)
let usbDeviceConfiguration = VZUSBMassStorageDeviceConfiguration(attachment: attachment)
return usbDeviceConfiguration
}

func createBootLoader() throws -> VZBootLoader {
let efi = VZEFIBootLoader()
let storeURL = vm.metadataDirectoryURL.appendingPathComponent("nvram")
if FileManager.default.fileExists(atPath: storeURL.path) {
efi.variableStore = VZEFIVariableStore(url: storeURL)
} else {
efi.variableStore = try VZEFIVariableStore(creatingVariableStoreAt: storeURL, options: [])
}
return efi
}

func createGraphicsDevices() -> [VZGraphicsDeviceConfiguration] {
let graphicsConfiguration = VZVirtioGraphicsDeviceConfiguration()

graphicsConfiguration.scanouts = vm.configuration.hardware.displayDevices.map(\.vzScanout)

return [graphicsConfiguration]
}
}

// MARK: - Configuration Models -> Virtualization

@available(macOS 13.0, *)
extension VBDisplayDevice {

var vzScanout: VZVirtioGraphicsScanoutConfiguration {
VZVirtioGraphicsScanoutConfiguration(widthInPixels: width, heightInPixels: height)
}

}
Loading