diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b355417..e9f3f98 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,16 +12,17 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v4 + with: + repository: "AsahiLinux/macvdmtool" - name: Build MacVDMTool run: | - cd macvdmtool make cc -o dfuTools_${{ matrix.arch }} main.o -framework CoreFoundation -framework IOKit -lc++ - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: dfuTools_${{ matrix.arch }} - path: macvdmtool/dfuTools_${{ matrix.arch }} + path: dfuTools_${{ matrix.arch }} retention-days: 5 build: needs: macvdmtool @@ -42,41 +43,44 @@ jobs: uses: actions/download-artifact@v4 with: name: dfuTools_arm64 - path: electron/dfuTools_arm64 + path: electron/ - name: Download Artifact (amd64) uses: actions/download-artifact@v4 with: name: dfuTools_amd64 - path: electron/dfuTools_x64 + path: electron/ - name: Chmod dfuTools run: | chmod +x electron/dfuTools_* + mkdir -p electron/dfuTools/x64 electron/dfuTools/arm64 + mv electron/dfuTools_amd64 electron/dfuTools/x64/dfuTools + mv electron/dfuTools_arm64 electron/dfuTools/arm64/dfuTools + chmod +x electron/dfuTools/x64/dfuTools electron/dfuTools/arm64/dfuTools - name: Build Release Files run: npm run pack env: GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} - - - name: Delete old Releases - uses: dev-drprasad/delete-older-releases@v0.3.2 + - name: Delete old Releases + uses: dev-drprasad/delete-older-releases@v0.3.3 with: repo: ${{ github.repository }} keep_latest: 3 delete_tag_pattern: "" env: GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} - - - name: 获取版本号 + + - name: 获取版本号 id: get-version run: | version=$(jq -r .version package.json) echo "version=${version}" >> $GITHUB_OUTPUT - - - name: Make release - uses: softprops/action-gh-release@v1 + + - name: Make release + uses: softprops/action-gh-release@v2 with: files: | release/${{ steps.get-version.outputs.version }}/DFU-Tools_x64.dmg @@ -89,4 +93,4 @@ jobs: tag_name: ${{ steps.get-version.outputs.version }} draft: false env: - GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} diff --git a/.gitignore b/.gitignore index 7179584..2d11add 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /release/ /node_modules /electron/dfuTools* -/macvdmtool/main.o +/macvdmtool/ diff --git a/docs/README.md b/docs/README.md index 3ea0e4a..33dfec9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,9 +13,9 @@ > [Github Release](https://github.com/XRSec/DFU-Tools/releases) > -> [镜像加速(Inter 1.1.8)](https://mirror.ghproxy.com/https://github.com/XRSec/DFU-Tools/releases/download/1.1.8/DFU-Tools_x64.dmg) +> [镜像加速(Inter 1.1.9)](https://mirror.ghproxy.com/https://github.com/XRSec/DFU-Tools/releases/download/1.1.9/DFU-Tools_x64.dmg) > -> [镜像加速(Apple 1.1.8)](https://mirror.ghproxy.com/https://github.com/XRSec/DFU-Tools/releases/download/1.1.8/DFU-Tools_arm64.dmg) +> [镜像加速(Apple 1.1.9)](https://mirror.ghproxy.com/https://github.com/XRSec/DFU-Tools/releases/download/1.1.9/DFU-Tools_arm64.dmg) ### 使用 / Usage diff --git a/electron-builder.json b/electron-builder.json index fb766c6..2ab8f0e 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -6,7 +6,7 @@ }, "files": [ "!icon.icns", - "!electron/dfuTools*", + "!electron/dfuTools", "!macvdmtool", "!docs", "!release", @@ -14,8 +14,8 @@ ], "extraFiles": [ { - "from": "electron/dfuTools_${arch}", - "to": "./Resources/dfuTools" + "from": "electron/dfuTools/${arch}/dfuTools", + "to": "./Resources/" } ], "artifactName": "${productName}_${arch}.${ext}", diff --git a/electron/index.js b/electron/index.js index 8f249b6..ec4d0d5 100644 --- a/electron/index.js +++ b/electron/index.js @@ -5,16 +5,13 @@ const {chmod, existsSync, lstatSync} = require("fs"); const prompt = require('electron-prompt'); const arch = process.arch === 'arm64' ? 'arm64' : 'x64'; -let dfuTools = join(__dirname, `dfuTools_${arch}`), +let dfuTools = join(__dirname, `dfuTools/${arch}/dfuTools`), admin_pass = '', configuratorStatus = false, win; if (__dirname.includes('/Contents/Resources/')) { - dfuTools = join(__dirname, '../../dfuTools') -} -if (!existsSync(dfuTools) || lstatSync(dfuTools).isDirectory()) { - dfuTools = join(dfuTools, `dfuTools_${arch}`) + dfuTools = join(__dirname, `../../dfuTools`) } console.debug(`dfuTools: ${dfuTools}`) @@ -110,17 +107,17 @@ ipcMain.on('openReboot', (event) => { return; } exec(`echo '${admin_pass}' | sudo -S ${dfuTools} reboot`, {encoding: 'utf-8'}, function (_error, stdout, _stderr) { - if (stdout.includes('No connection detected')) { + if (stdout?.includes('No connection detected')) { event.returnValue = "no_connection"; return; - } else if (stdout.includes('IOCreatePlugInInterfaceForService failed')) { + } else if (stdout?.includes('IOCreatePlugInInterfaceForService failed')) { event.returnValue = "no_admin_permission"; return; - } else if (_error.toString().includes('command not found')) { + } else if (_error?.toString().includes('command not found')) { event.returnValue = "no_dfu_permission"; return; } - console.debug(_error, _stderr) + console.debug(`error: ${_error} stderr: ${_stderr}`) event.returnValue = stdout; }) }) @@ -132,17 +129,18 @@ ipcMain.on('openDFU', (event) => { return; } exec(`echo '${admin_pass}' | sudo -S ${dfuTools} dfu`, {encoding: 'utf-8'}, function (_error, stdout, _stderr) { - if (stdout.includes('No connection detected')) { + console.log(_error) + if (stdout?.includes('No connection detected')) { event.returnValue = "no_connection"; return; - } else if (stdout.includes('IOCreatePlugInInterfaceForService failed')) { + } else if (stdout?.includes('IOCreatePlugInInterfaceForService failed')) { event.returnValue = "no_admin_permission"; return; - } else if (_error.toString().includes('command not found')) { + } else if (_error?.toString().includes('command not found')) { event.returnValue = "no_dfu_permission"; return; } - console.debug(_error, _stderr) + console.debug(`error: ${_error} stderr: ${_stderr}`) event.returnValue = stdout; }) }) diff --git a/macvdmtool/.clang-format b/macvdmtool/.clang-format deleted file mode 100644 index 5633567..0000000 --- a/macvdmtool/.clang-format +++ /dev/null @@ -1,9 +0,0 @@ -BasedOnStyle: LLVM -IndentWidth: 4 -UseTab: Never -BreakBeforeBraces: Linux -AllowShortIfStatementsOnASingleLine: Never -AllowShortFunctionsOnASingleLine: false -AlignConsecutiveMacros: true -IndentCaseLabels: true -ColumnLimit: 100 diff --git a/macvdmtool/.gitignore b/macvdmtool/.gitignore deleted file mode 100644 index d9a9ed6..0000000 --- a/macvdmtool/.gitignore +++ /dev/null @@ -1 +0,0 @@ -macvdmtool diff --git a/macvdmtool/AppleHPMLib.h b/macvdmtool/AppleHPMLib.h deleted file mode 100644 index e441982..0000000 --- a/macvdmtool/AppleHPMLib.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright © 2019 osy86. 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. -// - -#ifndef AppleHPMLib_h -#define AppleHPMLib_h - -#include - -#define kAppleHPMLibType \ - CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 0x12, 0xA1, 0xDC, 0xCF, 0xCF, 0x7A, 0x47, \ - 0x75, 0xBE, 0xE5, 0x9C, 0x43, 0x19, 0xF4, 0xCD, 0x2B) -#define kAppleHPMLibInterface \ - CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 0xC1, 0x3A, 0xCD, 0xD9, 0x20, 0x9E, 0x4B, \ - 0x01, 0xB7, 0xBE, 0xE0, 0x5C, 0xD8, 0x83, 0xC7, 0xB1) - -typedef struct { - IUNKNOWN_C_GUTS; - uint16_t field_20; - uint16_t field_22; - IOReturn (*Read)(void *, uint64_t chipAddr, uint8_t dataAddr, void *buffer, uint64_t maxLen, - uint32_t flags, uint64_t *readLen); - IOReturn (*Write)(void *, uint64_t chipAddr, uint8_t dataAd6dr, const void *buffer, - uint64_t len, uint32_t flags); - IOReturn (*Command)(void *, uint64_t chipAddr, uint32_t cmd, uint32_t flags); - IOReturn (*field_40)(void); - IOReturn (*field_48)(void); - IOReturn (*field_50)(void); -} AppleHPMLib; - -#endif /* AppleHPMLib_h */ diff --git a/macvdmtool/LICENSE b/macvdmtool/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/macvdmtool/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/macvdmtool/Makefile b/macvdmtool/Makefile deleted file mode 100644 index 0d770e1..0000000 --- a/macvdmtool/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -CXXFLAGS := -std=c++14 -LDFLAGS := -framework CoreFoundation -framework IOKit -lc++ - -OBJS := main.o - -all: macvdmtool - -macvdmtool: $(OBJS) - cc -o $@ $(OBJS) $(LDFLAGS) diff --git a/macvdmtool/README.md b/macvdmtool/README.md deleted file mode 100644 index a2774c4..0000000 --- a/macvdmtool/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Apple Silicon to Apple Silicon VDM tool - -This tool lets you get a serial console on an Apple Silicon device and reboot it remotely, using only another Apple Silicon device running macOS and a standard Type C cable. - -## Disclaimer - -I have no idea what I'm doing with IOKit and CoreFoundation -marcan - -## Copyright - -This is based on portions of [ThunderboltPatcher](https://github.com/osy/ThunderboltPatcher) and licensed under Apache-2.0. - -* Copyright (C) 2019 osy86. All rights reserved. -* Copyright (C) 2021 The Asahi Linux Contributors - -Thanks to t8012.dev and mrarm for assistance with the VDM and Ace2 host interface commands. - -## Note about macOS 12 - -To have access to the serial console device on macOS Monterey (12), you need to disable the `AppleSerialShim` extension. - -**Note:** This requires downgrading the system security and may cause problems with upgrades. Use it at your own risk! - -Start by generating a new kernel cache, without the `AppleSerialShim` extension: - -``` -sudo kmutil create -n boot -a arm64e -B /Library/KernelCollections/kc.noshim.macho -V release -k /System/Library/Kernels/kernel.release. -r /System/Library/Extensions -r /System/Library/DriverExtensions -x $(kmutil inspect -V release --no-header | awk '!/AppleSerialShim/ { print " -b "$1; }') -``` - -Replace `` with `t8101` on M1 Macs and `t6000` on M1 Pro/Max Macs. If you’re unsure, `uname -v` and look at the end of the version string (`RELEASE_ARM64_`). - -Then, enter 1TR: - -1. Power off your Mac -2. Press and hold the Power button until the boot menu appears -3. Select “Options”, then (if necessary) select your macOS volume and enter your administrative password. - -Select Utilities>Startup security and switch the macOS installation to reduced security. Exit Startup security. - -Select Utilities>Terminal and install your custom kernel: - -``` -kmutil configure-boot -c /Volume//Library/KernelCollections/kc.noshim.macho -C -v /Volume/ -``` - -Replace `` with the name of your boot volume. - -You can now reboot: macOS should start as normal, and the serial device `/dev/cu.debug-console` should be available. - -To revert back to the default kernel, enter 1TR again, access Utilities>Startup security and switch to full or reduced security. - -## Building - -Install the XCode commandline tools and type `make`. - -## Usage - -Connect the two devices via their DFU ports. That's: - - the rear port on MacBook Air and 13" MacBook Pro - - the port next to the MagSafe connector on the 14" and 16" MacBook Pro - - the port nearest to the power plug on Mac Mini - -You need to use a *USB 3.0 compatible* (SuperSpeed) Type C cable. USB 2.0-only cables, including most cables meant for charging, will not work, as they do not have the required pins. Thunderbolt cables work too. - -Run it as root (`sudo ./macvdmtool`). - -``` -Usage: ./macvdmtool -Commands: - serial - enter serial mode on both ends - reboot - reboot the target - reboot serial - reboot the target and enter serial mode - dfu - put the target into DFU mode - nop - do nothing -``` - -Use `/dev/cu.debug_console` on the local machine as your serial device. To use it with m1n1, `export M1N1DEVICE=/dev/cu.debug-console`. - -For typical development, the command you want to use is `macvdmtool reboot serial`. This will reboot the target, and immediately put it back into serial mode, with the right timing to make it work. diff --git a/macvdmtool/main.cpp b/macvdmtool/main.cpp deleted file mode 100644 index 6b649b4..0000000 --- a/macvdmtool/main.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* Based on https://github.com/osy/ThunderboltPatcher */ - -#include "AppleHPMLib.h" -#include "ssops.h" -#include -#include -#include -#include -#include - -#include -#include - -struct failure : public std::runtime_error { - failure(const char *x) : std::runtime_error(x) - { - } -}; - -struct IOObjectDeleter { - io_object_t arg; - - IOObjectDeleter(io_object_t arg) : arg(arg) - { - } - - ~IOObjectDeleter() - { - IOObjectRelease(arg); - } -}; - -struct HPMPluginInstance { - IOCFPlugInInterface **plugin = nullptr; - AppleHPMLib **device; - - HPMPluginInstance(io_service_t service) - { - SInt32 score; - IOReturn ret = IOCreatePlugInInterfaceForService(service, kAppleHPMLibType, - kIOCFPlugInInterfaceID, &plugin, &score); - if (ret != kIOReturnSuccess) - throw failure("IOCreatePlugInInterfaceForService failed"); - - HRESULT res = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kAppleHPMLibInterface), - (LPVOID *)&device); - if (res != S_OK) - throw failure("QueryInterface failed"); - } - - ~HPMPluginInstance() - { - if (plugin) { - printf("Exiting DBMa mode... "); - if (this->command(0, 'DBMa', "\x00") == 0) - printf("OK\n"); - else - printf("Failed\n"); - IODestroyPlugInInterface(plugin); - } - } - - std::string readRegister(uint64_t chipAddr, uint8_t dataAddr, int flags = 0) - { - std::string ret; - ret.resize(64); - uint64_t rlen = 0; - IOReturn x = (*device)->Read(device, chipAddr, dataAddr, &ret[0], 64, flags, &rlen); - if (x != 0) - throw failure("readRegister failed"); - return ret; - } - - void writeRegister(uint64_t chipAddr, uint8_t dataAddr, std::string value) - { - IOReturn x = (*device)->Write(device, chipAddr, dataAddr, &value[0], value.length(), 0); - if (x != 0) - throw failure("writeRegister failed"); - } - - int command(uint64_t chipAddr, uint32_t cmd, std::string args = "") - { - if (args.length()) - (*device)->Write(device, chipAddr, 9, args.data(), args.length(), 0); - auto ret = (*device)->Command(device, chipAddr, cmd, 0); - if (ret) - return -1; - auto res = this->readRegister(chipAddr, 9); - return res[0] & 0xfu; - } -}; - -uint32_t GetUnlockKey() -{ - CFMutableDictionaryRef matching = IOServiceMatching("IOPlatformExpertDevice"); - if (!matching) - throw failure("IOServiceMatching failed (IOPED)"); - - io_iterator_t iter = 0; - IOObjectDeleter iterDel(iter); - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); - if (!service) - throw failure("IOServiceGetMatchingService failed (IOPED)"); - - IOObjectDeleter deviceDel(service); - - io_name_t deviceName; - if (IORegistryEntryGetName(service, deviceName) != kIOReturnSuccess) { - throw failure("IORegistryEntryGetName failed (IOPED)"); - } - - printf("Mac type: %s\n", deviceName); - - return (deviceName[0] << 24) | (deviceName[1] << 16) | (deviceName[2] << 8) | deviceName[3]; -} - -std::unique_ptr FindDevice() -{ - std::unique_ptr ret; - - printf("Looking for HPM devices...\n"); - - CFMutableDictionaryRef matching = IOServiceMatching("AppleHPM"); - if (!matching) - throw failure("IOServiceMatching failed"); - - io_iterator_t iter = 0; - IOObjectDeleter iterDel(iter); - if (IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iter) != kIOReturnSuccess) - throw failure("IOServiceGetMatchingServices failed"); - - io_service_t device; - while ((device = IOIteratorNext(iter))) { - IOObjectDeleter deviceDel(device); - io_string_t pathName; - - if (IORegistryEntryGetPath(device, kIOServicePlane, pathName) != kIOReturnSuccess) { - fprintf(stderr, "Failed to get device path for object %d.", device); - continue; - } - - CFNumberRef data; - int32_t rid; - data = (CFNumberRef)IORegistryEntryCreateCFProperty(device, CFSTR("RID"), - kCFAllocatorDefault, 0); - if (!data) - throw failure("No RID"); - - CFNumberGetValue(data, kCFNumberSInt32Type, &rid); - CFRelease(data); - - // RID=0 seems to always be the right port - if (rid != 0) - continue; - - printf("Found: %s\n", pathName); - ret = std::make_unique(device); - } - - if (!ret) - throw failure("No matching devices"); - - return ret; -}; - -void UnlockAce(HPMPluginInstance &inst, int no, uint32_t key) -{ - printf("Unlocking... "); - std::stringstream args; - put(args, key); - if (inst.command(no, 'LOCK', args.str())) { - printf(" Failed.\n"); - printf("Trying to reset... "); - if (inst.command(no, 'Gaid')) { - printf("Failed.\n"); - throw failure("Failed to unlock device"); - } - printf("OK.\nUnlocking... "); - if (inst.command(no, 'LOCK', args.str())) { - printf(" Failed.\n"); - throw failure("Failed to unlock device"); - } - } - - printf("OK\n"); -} - -void DoVDM(HPMPluginInstance &inst, int no, std::vector vdm) -{ - - auto rs = inst.readRegister(no, 0x4d); - uint8_t rxst = rs[0]; - - std::stringstream args; - put(args, (uint8_t)(((3 << 4) | vdm.size()))); - for (uint32_t i : vdm) - put(args, i); - - auto v = args.str(); - - if (inst.command(no, 'VDMs', args.str())) - throw failure("Failed to send VDM\n"); - - int i; - for (i = 0; i < 16; i++) { - rs = inst.readRegister(no, 0x4d); - if ((uint8_t)rs[0] != rxst) - break; - } - if (i >= 16) - throw failure("Did not get a reply to VDM\n"); - - uint32_t vdmhdr; - std::stringstream reply; - reply.str(rs); - get(reply, rxst); - get(reply, vdmhdr); - - if (vdmhdr != (vdm[0] | 0x40)) { - printf("VDM failed (reply: 0x%08x)\n", vdmhdr); - throw failure("VDM failed"); - } -} - -int DoSerial(HPMPluginInstance &inst, int no) -{ - printf("Putting target into serial mode... "); - - std::vector serial{0x5ac8012, 0x1840306}; - DoVDM(inst, no, serial); - - printf("OK\n"); - - printf("Putting local end into serial mode... "); - - std::stringstream args; - put(args, (uint32_t)0x1840306); - - if (inst.command(no, 'DVEn', args.str())) { - printf("Failed.\n"); - return 1; - } - printf("OK\n"); - - return 0; -} - -int DoReboot(HPMPluginInstance &inst, int no) -{ - printf("Rebooting target into normal mode... "); - - std::vector reboot{0x5ac8012, 0x105, 0x80000000}; - DoVDM(inst, no, reboot); - - printf("OK\n"); - return 0; -} - -int DoRebootSerial(HPMPluginInstance &inst, int no) -{ - - if (DoReboot(inst, no)) - return 1; - - printf("Waiting for connection..."); - fflush(stdout); - - sleep(1); - int i; - for (i = 0; i < 30; i++) { - printf("."); - fflush(stdout); - auto t = inst.readRegister(no, 0x3f); - if (t[0] & 1) - break; - usleep(100000); - } - if (i >= 30) { - printf(" Timed out\n"); - return 1; - } - printf(" Connected\n"); - sleep(1); - - return DoSerial(inst, no); -} - -int DoDFU(HPMPluginInstance &inst, int no) -{ - printf("Rebooting target into DFU mode... "); - - std::vector dfu{0x5ac8012, 0x106, 0x80010000}; - DoVDM(inst, no, dfu); - - printf("OK\n"); - return 0; -} - -int main2(int argc, char **argv) -{ - if (argc < 2) { - printf("Usage: %s \n", argv[0]); - printf("Commands:\n"); - printf(" serial - enter serial mode on both ends\n"); - printf(" reboot - reboot the target\n"); - printf(" reboot serial - reboot the target and enter serial mode\n"); - printf(" dfu - put the target into DFU mode\n"); - printf(" nop - do nothing\n"); - return 1; - } - - uint32_t key = GetUnlockKey(); - - auto inst = FindDevice(); - int no = 0; - - auto t = inst->readRegister(no, 0x3f); - std::string type = (t[0] & 1) ? ((t[0] & 2) == 0 ? "Source" : "Sink") : "None"; - printf("Connection: %s\n", type.c_str()); - - if (!(t[0] & 1)) - throw failure("No connection detected"); - - auto res = inst->readRegister(no, 0x03); - res.erase(res.find('\0')); - printf("Status: %s\n", res.c_str()); - - if (res != "DBMa") { - UnlockAce(*inst, no, key); - printf("Entering DBMa mode... "); - - if (inst->command(no, 'DBMa', "\x01")) - throw failure("Failed to enter DBMa mode"); - - res = inst->readRegister(no, 0x03); - res.erase(res.find('\0')); - - printf("Status: %s\n", res.c_str()); - if (res != "DBMa") - throw failure("Failed to enter DBMa mode"); - } - - std::string cmd = argv[1]; - std::string arg = ""; - - if (argc >= 3) - arg = argv[2]; - - if (cmd == "serial") - return DoSerial(*inst, no); - else if (cmd == "reboot") { - if (arg == "serial") - return DoRebootSerial(*inst, no); - else - return DoReboot(*inst, no); - } else if (cmd == "dfu") - return DoDFU(*inst, no); - else if (cmd == "nop") - return 0; - - printf("Unknown command\n"); - return 1; -} - -int main(int argc, char **argv) -{ - // This makes sure we call the HPMPluginInstance destructor. - try { - return main2(argc, argv); - } catch (failure e) { - printf("%s\n", e.what()); - return -1; - } -} diff --git a/macvdmtool/ssops.h b/macvdmtool/ssops.h deleted file mode 100644 index b38d163..0000000 --- a/macvdmtool/ssops.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* Based on https://github.com/osy/ThunderboltPatcher */ - -#include -#include -#include - -template std::stringstream &put(std::stringstream &str, const T &value) -{ - union coercion { - T value; - char data[sizeof(T)]; - }; - - coercion c; - - c.value = value; - - str.write(c.data, sizeof(T)); - - return str; -} - -template std::stringstream &get(std::stringstream &str, T &value) -{ - union coercion { - T value; - char data[sizeof(T)]; - }; - - coercion c; - - c.value = value; - - str.read(c.data, sizeof(T)); - - value = c.value; - - return str; -} diff --git a/package-lock.json b/package-lock.json index 01ee0b0..69d6965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "dfu-tools", - "version": "1.1.8", + "version": "1.1.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dfu-tools", - "version": "1.1.8", + "version": "1.1.9", "license": "apache-2.0", "dependencies": { "electron-prompt": "^1.7.0" }, "devDependencies": { - "electron": "^29.1.1", + "electron": "^30.0.1", "electron-builder": "^24.13.3" } }, @@ -1513,9 +1513,9 @@ "dev": true }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "dependencies": { "jake": "^10.8.5" @@ -1528,9 +1528,9 @@ } }, "node_modules/electron": { - "version": "29.1.1", - "resolved": "https://registry.npmmirror.com/electron/-/electron-29.1.1.tgz", - "integrity": "sha512-cXN15NgCi7MkzGo5/23ZQbii+0UfhmUiDjACunmzcUofYCjF42XhFbL7JZnwgI0qtBCCeJU8qZNZt9lU91gUFw==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-30.0.1.tgz", + "integrity": "sha512-iwxkI/n2wBd29NH7TH0ZY8aWGzCoKpzJz+D10u7aGSJi1TV6d4MSM3rWyKvT/UkAHkTKOEgYfUyCa2vWQm8L0g==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index 42fb156..3b36c87 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "dfu-tools", "productName": "DFU-Tools", - "version": "1.1.8", + "version": "1.1.9", "description": "macOS DFU TOOLS", "main": "electron/index.js", "scripts": { @@ -27,7 +27,7 @@ }, "license": "apache-2.0", "devDependencies": { - "electron": "^29.1.1", + "electron": "^30.0.1", "electron-builder": "^24.13.3" }, "dependencies": {