Skip to content

Commit

Permalink
Merge branch 'main' into utm-import
Browse files Browse the repository at this point in the history
  • Loading branch information
osy authored Nov 20, 2024
2 parents bfecac3 + 28a14b9 commit f11cda7
Show file tree
Hide file tree
Showing 50 changed files with 1,568 additions and 1,322 deletions.
30 changes: 21 additions & 9 deletions Configuration/UTMAppleConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ final class UTMAppleConfiguration: UTMConfiguration {
@Published private var _networks: [UTMAppleConfigurationNetwork] = [.init()]

@Published private var _serials: [UTMAppleConfigurationSerial] = []


/// Set to true to request guest tools install. Not saved.
@Published var isGuestToolsInstallRequested: Bool = false

var backend: UTMBackend {
.apple
}
Expand Down Expand Up @@ -251,13 +254,7 @@ extension UTMAppleConfiguration {
let vzconfig = VZVirtualMachineConfiguration()
try system.fillVZConfiguration(vzconfig)
if #available(macOS 12, *), !sharedDirectories.isEmpty {
let tag: String
if #available(macOS 13, *), system.boot.operatingSystem == .macOS {
tag = VZVirtioFileSystemDeviceConfiguration.macOSGuestAutomountTag
} else {
tag = "share"
}
let fsConfig = VZVirtioFileSystemDeviceConfiguration(tag: tag)
let fsConfig = VZVirtioFileSystemDeviceConfiguration(tag: shareDirectoryTag)
fsConfig.share = UTMAppleConfigurationSharedDirectory.makeDirectoryShare(from: sharedDirectories)
vzconfig.directorySharingDevices.append(fsConfig)
} else if !sharedDirectories.isEmpty {
Expand All @@ -269,7 +266,11 @@ extension UTMAppleConfiguration {
return nil
}
if #available(macOS 13, *), drive.isExternal {
return VZUSBMassStorageDeviceConfiguration(attachment: attachment)
if #available(macOS 15, *) {
return nil // we will handle removable drives in `UTMAppleVirtualMachine`
} else {
return VZUSBMassStorageDeviceConfiguration(attachment: attachment)
}
} else if #available(macOS 14, *), drive.isNvme, system.boot.operatingSystem == .linux {
return VZNVMExpressControllerDeviceConfiguration(attachment: attachment)
} else {
Expand Down Expand Up @@ -303,8 +304,19 @@ extension UTMAppleConfiguration {
} else if system.boot.operatingSystem != .macOS && !displays.isEmpty {
throw UTMAppleConfigurationError.featureNotSupported
}
if #available(macOS 15, *) {
vzconfig.usbControllers = [VZXHCIControllerConfiguration()]
}
return vzconfig
}

var shareDirectoryTag: String {
if #available(macOS 13, *), system.boot.operatingSystem == .macOS {
return VZVirtioFileSystemDeviceConfiguration.macOSGuestAutomountTag
} else {
return "share"
}
}
}

// MARK: - Saving data
Expand Down
4 changes: 4 additions & 0 deletions Configuration/UTMAppleConfigurationSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ struct UTMAppleConfigurationSystem: Codable {
boot = try values.decode(UTMAppleConfigurationBoot.self, forKey: .boot)
macPlatform = try values.decodeIfPresent(UTMAppleConfigurationMacPlatform.self, forKey: .macPlatform)
genericPlatform = try values.decodeIfPresent(UTMAppleConfigurationGenericPlatform.self, forKey: .genericPlatform)
if boot.operatingSystem == .linux && genericPlatform == nil {
// fix a bug where this was not created
genericPlatform = UTMAppleConfigurationGenericPlatform()
}
}

func encode(to encoder: Encoder) throws {
Expand Down
2 changes: 1 addition & 1 deletion Configuration/UTMAppleConfigurationVirtualization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ extension UTMAppleConfigurationVirtualization {
throw UTMAppleConfigurationError.rosettaNotSupported
}
#endif
if hasClipboardSharing && !isMacOSGuest {
if hasClipboardSharing {
let spiceClipboardAgent = VZSpiceAgentPortAttachment()
spiceClipboardAgent.sharesClipboard = true
let consolePort = VZVirtioConsolePortConfiguration()
Expand Down
2 changes: 1 addition & 1 deletion Configuration/UTMQemuConfiguration+Arguments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ import Virtualization // for getting network interfaces
f()
} else if drive.interface == .scsi {
var bus = "scsi"
if system.architecture != .sparc && system.architecture != .sparc64 {
if system.architecture != .sparc && system.architecture != .sparc64 && system.architecture != .m68k {
bus = "scsi0"
if busindex == 0 {
f("-device")
Expand Down
3 changes: 3 additions & 0 deletions Configuration/UTMQemuConfigurationQEMU.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//

import Foundation
import System

/// Tweaks and advanced QEMU settings.
struct UTMQemuConfigurationQEMU: Codable {
Expand Down Expand Up @@ -189,6 +190,8 @@ extension UTMQemuConfigurationQEMU {
if !fileManager.fileExists(atPath: varsURL.path) {
try await Task.detached {
try FileManager.default.copyItem(at: templateVarsURL, to: varsURL)
let permissions: FilePermissions = [.ownerReadWrite, .groupRead, .otherRead]
try FileManager.default.setAttributes([.posixPermissions: permissions.rawValue], ofItemAtPath: varsURL.path)
}.value
}
efiVarsURL = varsURL
Expand Down
2 changes: 1 addition & 1 deletion Documentation/MacDevelopment.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ git submodule update --init --recursive

## Dependencies

The easy way is to get the prebuilt dependences from [GitHub Actions][1]. Pick the latest release and download all of the `Sysroot-macos-*` artifacts. You need to be logged in to GitHub to download artifacts. If you only intend to run locally, it is alright to just download the sysroot for your architecture. After downloading the prebuilt artifacts of your choice, extract them to the root directory where you cloned the repository.
The easy way is to get the prebuilt dependencies from [GitHub Actions][1]. Pick the latest release and download all of the `Sysroot-macos-*` artifacts. You need to be logged in to GitHub to download artifacts. If you only intend to run locally, it is alright to just download the sysroot for your architecture. After downloading the prebuilt artifacts of your choice, extract them to the root directory where you cloned the repository.

To build UTM, make sure you have the latest version of Xcode installed.

Expand Down
66 changes: 33 additions & 33 deletions Documentation/TetheredLaunch.zh-HK.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
# 不完全啟動
# 捆綁式啟動

在iOS14中,Apple[修補][1]了我們用來使JIT工作的“把戲”。 因此,下一個最佳的解決方案所涉及的範圍更廣。 這只支援非越獄設備。 如果你越獄了,你不需要這樣做
在 iOS 14 當中,Apple [修複][1]了我們之前令 JIT 工作的“蠱惑招”。因此,下一個最佳的變通方法涉及更多。這只限用於未越獄的裝置。如你已經越獄,就無需這樣做

## 前條件
## 先決條件

* Xcode
* [最新的正用版IPA][3]
* [iOS App Signer][4]
* [Homebrew][2]
* [ios-deploy][5] (`brew install ios-deploy`)
* Xcode
* [最新版本的 IPA][3]
* [iOS App Signer][4]
* [Homebrew][2]
* [ios-deploy][5] (`brew install ios-deploy`)

## 簽字
## 簽署

安裝並按照[iOS App Signer][4]的說明進行操作。 請確保您的簽字證書和配置文件匹配。 選擇UTM.ipa正式版作為輸入文件並且按下開始
安裝並依照 [iOS App Signer][4] 的說明執行操作。確保你的簽署證書與配置檔案匹配。選擇 UTM.ipa 發行版本作為輸入檔案,然後按一下「開始」

將已簽字的IPA保存為`UTM-signed.ipa`過程完成後將`UTM-signed.ipa`重命名為`UTM-signed.zip`並且打開ZIP文件。 macOS會將文件提取至名為`Payload/`的新目錄
將已經簽署的 IPA 儲存為 `UTM-signed.ipa`完成程序之後,將 `UTM-signed.ipa` 重新命名為`UTM-signed.zip`,並且開啟 ZIP 檔案。macOS 應將檔案解壓縮至名稱為 `Payload/` 的新目錄當中

## 部署
## 部署

要部署UTM,連接你的設備然後在終端中運行
如要部署 UTM,連接你的裝置並在終端機中執行

```sh
ios-deploy --bundle /path/to/Payload/UTM.app
```
```sh
ios-deploy --bundle /path/to/Payload/UTM.app
```

(提示:你可以把 `Payload/UTM.app` 拖放進終端來自動填充目錄。)
(貼士:你可以拖放 `Payload/UTM.app` 至終端機以自動填充目錄。)

## 啟動
## 啟動

當你每次希望啟動UTM時,都需要運行以下命令。 (你無法在iOS14中從主頁面正常啟動UTM否則它無法正常運行!)
如你每次希望啟動 UTM,都需要執行以下內容。(在 iOS 14 當中,不應該透過主畫面啟動 UTM,否則它將無法正常工作!)

```sh
ios-deploy --justlaunch --noinstall --bundle /path/to/Payload/UTM.app
```
```sh
ios-deploy --justlaunch --noinstall --bundle /path/to/Payload/UTM.app
```

(提示:如果您打開Xcode並轉到Window->Devices and Simulators並找到您的設備,那麼您可以選中“Connect via network”(通過網路連接)以便在沒有USB連線的情況下部署/啟動。你只 需要解鎖設備並靠近你的電腦。)
(貼士:如你要開啟 Xcode 並轉到 Window > Devices and Simulators 找到你的裝置,則你可以選中「Connect via network」以便於在無 USB 連線的條件下部署/啟動。你只需要解鎖裝置並令它靠近你的電腦。)

## 疑難解答
## 疑難排解

### 信任問題
### 信任問題

如果你看見了消息`The operation couldn't be completed. Unable to launch xxx because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user.(無法完成操作。無法啟動xxx, 因為它的代碼簽名無效、授權不足或其配置文件未被用戶明確信任。 )`,你需要打開設置-> 通用-> 設備管理,選擇開發者描述文件,然後選擇信任
如你看到訊息`The operation couldn't be completed. Unable to launch xxx because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user.`,你需要開啟設定 > 一般 > 裝置管理,選擇「開發者描述檔」,然後選擇「信任」

### 註冊捆綁標識符失敗
### 註冊套裝識別碼失敗(Failed to register bundle identifier)

Xcode 可能在嘗試創建簽名配置文件時顯示此消息,您需要更改綁定標識符並重試
Xcode 可能在嘗試製作簽名設定檔時顯示此訊息,你需要更改套裝識別碼,然後再試

[1]: https://github.com/utmapp/UTM/issues/397
[2]: https://brew.sh
[3]: https://github.com/utmapp/UTM/releases
[4]: https://dantheman827.github.io/ios-app-signer/
[5]: https://github.com/ios-control/ios-deploy
[1]: https://github.com/utmapp/UTM/issues/397
[2]: https://brew.sh
[3]: https://github.com/utmapp/UTM/releases
[4]: https://dantheman827.github.io/ios-app-signer/
[5]: https://github.com/ios-control/ios-deploy
24 changes: 12 additions & 12 deletions Documentation/TetheredLaunch.zh-Hans.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
# 不完美启动
# 捆绑启动

在iOS14中,苹果[修补][1]了我们用来让JIT工作的“把戏”。因此,下一个最佳的解决方案所涉及的范围更广。这只适用于非越狱设备。 如果你越狱了,你不需要这样做
在 iOS 14 中,Apple [修补][1]了我们用来让 JIT 工作的“把戏”。因此,下一个最佳的解决方案所涉及的范围更广。这一操作只适用于非越狱设备。如果你已经越狱,就不需要这样做了

## 前置条件

* Xcode
* [最新的正式版IPA][3]
* [最新版本的 IPA][3]
* [iOS App Signer][4]
* [Homebrew][2]
* [ios-deploy][5] (`brew install ios-deploy`)

## 签名

安装并按照[iOS App Signer][4]的说明进行操作。请确保您的签名证书和配置文件匹配。 选择UTM.ipa正式版作为输入文件并且按下开始
安装并按照 [iOS App Signer][4] 的说明进行操作。确保你的签名证书和配置文件相匹配。选择 UTM.ipa 版本作为输入的文件,然后点击“开始”

将已签名的IPA保存为`UTM-signed.ipa`过程完成后将`UTM-signed.ipa`重命名为`UTM-signed.zip`并且打开ZIP文件。 macOS会将文件提取至名为`Payload/`的新目录
将已签名的 IPA 保存为 `UTM-signed.ipa`完成操作后将 `UTM-signed.ipa` 重命名为 `UTM-signed.zip`,打开 ZIP 文件。 macOS 会将文件提取到名为`Payload/`的新目录中

## 部署

要部署UTM,连接你的设备然后在终端中运行
若要部署 UTM,请连接你的设备,然后在终端中运行

```sh
ios-deploy --bundle /path/to/Payload/UTM.app
```

(提示:你可以把 `Payload/UTM.app` 拖放进终端来自动填充目录。)
提示:你可以把 `Payload/UTM.app` 拖放进终端来自动填充目录。

## 启动

当你每次希望启动UTM时,都需要运行以下命令。 (你无法在iOS14中从主屏幕正常启动UTM否则它无法正常运行!)
当你每次希望启动 UTM 时,都需要运行如下命令。(不能在 iOS 14 中从主屏幕启动 UTM,否则它将无法正常工作!)

```sh
ios-deploy --justlaunch --noinstall --bundle /path/to/Payload/UTM.app
```

(提示:如果您打开Xcode并转到Window->Devices and Simulators并找到您的设备,那么您可以选中“Connect via network”(通过网络连接)以便在没有USB电缆的情况下部署/启动。你只需要解锁设备并靠近你的电脑。)
提示:如果你打开了 Xcode 并转到窗口(Window)> 设备和模拟器(Devices and Simulators)并找到你的设备,可以勾选“通过网络连接”,以便在没有 USB 电缆的情况下部署/启动。只需要解锁设备并靠近你的电脑即可。)

## 疑难解答

### 信任问题

如果你看见了消息:`The operation couldn’t be completed. Unable to launch xxx because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user.(无法完成操作。无法启动xxx,因为它的代码签名无效、授权不足或其配置文件未被用户明确信任。 `,你需要打开设置 -> 通用 -> 设备管理,选择开发者描述文件,然后选择信任。
如果你看到了消息 `The operation couldn’t be completed. Unable to launch xxx because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user.(无法完成操作。无法启动 xxx,因为它的代码签名无效,授权不足,或者其配置文件尚未被用户明确信任。`,你需要打开设置 > 通用 > 设备管理,选择开发者描述文件,然后选择信任。

### 注册捆绑标识符失败
### 注册捆绑包标识符失败(Failed to register bundle identifier)

Xcode 可能在尝试创建签名配置文件时显示此消息,您需要更改绑定标识符并重试
Xcode 可能在尝试创建签名配置文件时显示此消息,你需要更改绑定标识符并重试

[1]: https://github.com/utmapp/UTM/issues/397
[2]: https://brew.sh
Expand Down
11 changes: 9 additions & 2 deletions Platform/Shared/BusyOverlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ struct BusyOverlay: View {
EmptyView()
}
}
.alert(item: $data.alertMessage) { alertMessage in
Alert(title: Text(alertMessage.message))
.alert(item: $data.alertItem) { item in
switch item {
case .downloadUrl(let url):
return Alert(title: Text("Download VM"), message: Text("Do you want to download '\(url)'?"), primaryButton: .cancel(), secondaryButton: .default(Text("Download")) {
data.downloadUTMZip(from: url)
})
case .message(let message):
return Alert(title: Text(message))
}
}
}
}
Expand Down
28 changes: 3 additions & 25 deletions Platform/Shared/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ struct ContentView: View {
@State private var editMode = false
@EnvironmentObject private var data: UTMData
@StateObject private var releaseHelper = UTMReleaseHelper()
@State private var newPopupPresented = false
@State private var openSheetPresented = false
@State private var alertItem: AlertItem?
@Environment(\.openURL) var openURL
@AppStorage("ServerAutostart") private var isServerAutostart: Bool = false

Expand All @@ -55,14 +53,6 @@ struct ContentView: View {
}, content: {
VMReleaseNotesView(helper: releaseHelper).padding()
})
.alert(item: $alertItem) { item in
switch item {
case .downloadUrl(let url):
return Alert(title: Text("Download VM"), message: Text("Do you want to download '\(url)'?"), primaryButton: .cancel(), secondaryButton: .default(Text("Download")) {
data.downloadUTMZip(from: url)
})
}
}
.onReceive(NSNotification.ShowReleaseNotes) { _ in
Task {
await releaseHelper.fetchReleaseNotes(force: true)
Expand Down Expand Up @@ -148,8 +138,9 @@ struct ContentView: View {
components.host == "downloadVM",
let urlParameter = components.queryItems?.first(where: { $0.name == "url" })?.value,
let url = URL(string: urlParameter) {
if alertItem == nil {
alertItem = .downloadUrl(url)
if data.alertItem == nil {
data.showNewVMSheet = false
data.alertItem = .downloadUrl(url)
}
} else if url.isFileURL {
data.busyWorkAsync {
Expand Down Expand Up @@ -214,19 +205,6 @@ extension ContentView: DropDelegate {
}
}

extension ContentView {
private enum AlertItem: Identifiable {
case downloadUrl(URL)

var id: Int {
switch self {
case .downloadUrl(let url):
return url.hashValue
}
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
Expand Down
9 changes: 9 additions & 0 deletions Platform/Shared/VMContextMenuModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,14 @@ struct VMContextMenuModifier: ViewModifier {
}
}
}
#if os(macOS)
.onChange(of: (vm.config as? UTMAppleConfiguration)?.isGuestToolsInstallRequested) { newValue in
if newValue == true {
data.busyWorkAsync {
try await data.mountSupportTools(for: vm.wrapped!)
}
}
}
#endif
}
}
13 changes: 12 additions & 1 deletion Platform/Shared/VMWizardState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ enum VMBootDevice: Int, Identifiable {
case kernel
}

struct AlertMessage: Identifiable {
var message: String
public var id: String {
message
}

init(_ message: String) {
self.message = message
}
}

@MainActor class VMWizardState: ObservableObject {
let bytesInMib = 1048576
let bytesInGib = 1073741824
Expand Down Expand Up @@ -325,14 +336,14 @@ enum VMBootDevice: Int, Identifiable {
bootloader.linuxInitialRamdiskURL = linuxInitialRamdiskURL
bootloader.linuxCommandLine = linuxBootArguments
config.system.boot = bootloader
config.system.genericPlatform = UTMAppleConfigurationGenericPlatform()
if let linuxRootImageURL = linuxRootImageURL {
config.drives.append(UTMAppleConfigurationDrive(existingURL: linuxRootImageURL))
isSkipDiskCreate = true
}
} else {
config.system.boot = try UTMAppleConfigurationBoot(for: .linux)
}
config.system.genericPlatform = UTMAppleConfigurationGenericPlatform()
config.virtualization.hasRosetta = linuxHasRosetta
#endif
case .Windows:
Expand Down
Loading

0 comments on commit f11cda7

Please sign in to comment.