diff --git a/OC/ACPI/SSDT-AWAC.aml b/OC/ACPI/SSDT-AWAC.aml index 5189bf4..3698381 100644 Binary files a/OC/ACPI/SSDT-AWAC.aml and b/OC/ACPI/SSDT-AWAC.aml differ diff --git a/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml b/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml deleted file mode 100644 index fc27e3a..0000000 Binary files a/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml and /dev/null differ diff --git a/OC/ACPI/SSDT-EC.aml b/OC/ACPI/SSDT-EC.aml new file mode 100644 index 0000000..877de34 Binary files /dev/null and b/OC/ACPI/SSDT-EC.aml differ diff --git a/OC/ACPI/SSDT-GPRW.aml b/OC/ACPI/SSDT-GPRW.aml new file mode 100644 index 0000000..0c51dd8 Binary files /dev/null and b/OC/ACPI/SSDT-GPRW.aml differ diff --git a/OC/ACPI/SSDT-HPET.aml b/OC/ACPI/SSDT-HPET.aml new file mode 100644 index 0000000..5a61ef9 Binary files /dev/null and b/OC/ACPI/SSDT-HPET.aml differ diff --git a/OC/ACPI/SSDT-PLUG-ALT.aml b/OC/ACPI/SSDT-PLUG-ALT.aml index a95705e..cb5e20e 100644 Binary files a/OC/ACPI/SSDT-PLUG-ALT.aml and b/OC/ACPI/SSDT-PLUG-ALT.aml differ diff --git a/OC/ACPI/SSDT-RHUB.aml b/OC/ACPI/SSDT-RHUB.aml deleted file mode 100644 index 61e45cc..0000000 Binary files a/OC/ACPI/SSDT-RHUB.aml and /dev/null differ diff --git a/OC/ACPI/SSDT-SBUS-MCHC.aml b/OC/ACPI/SSDT-SBUS-MCHC.aml new file mode 100644 index 0000000..edb8a41 Binary files /dev/null and b/OC/ACPI/SSDT-SBUS-MCHC.aml differ diff --git a/OC/ACPI/SSDT-USBW.aml b/OC/ACPI/SSDT-USBW.aml new file mode 100644 index 0000000..7171cef Binary files /dev/null and b/OC/ACPI/SSDT-USBW.aml differ diff --git a/OC/ACPI/SSDT-USBX.aml b/OC/ACPI/SSDT-USBX.aml new file mode 100644 index 0000000..ca66962 Binary files /dev/null and b/OC/ACPI/SSDT-USBX.aml differ diff --git a/OC/Kexts/USBMap.kext/Contents/Info.plist b/OC/Kexts/USBMap.kext/Contents/Info.plist new file mode 100644 index 0000000..87952fd --- /dev/null +++ b/OC/Kexts/USBMap.kext/Contents/Info.plist @@ -0,0 +1,204 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleGetInfoString + v1.0 + CFBundleIdentifier + com.corpnewt.USBMap + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + USBMap + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + IOKitPersonalities + + iMacPro1,1-XHCI + + CFBundleIdentifier + com.apple.driver.AppleUSBHostMergeProperties + IOClass + AppleUSBHostMergeProperties + IOParentMatch + + IOPropertyMatch + + pcidebug + 0:20:0 + + + IOProviderClass + AppleUSBXHCIPCI + IOProviderMergeProperties + + kUSBMuxEnabled + + port-count + + DQAAAA== + + ports + + HS01 + + UsbConnector + 0 + port + + AQAAAA== + + + HS02 + + UsbConnector + 0 + port + + AgAAAA== + + + HS03 + + UsbConnector + 0 + port + + AwAAAA== + + + HS04 + + #port + + BAAAAA== + + UsbConnector + 3 + + HS05 + + UsbConnector + 255 + port + + BQAAAA== + + + HS06 + + UsbConnector + 255 + port + + BgAAAA== + + + HS07 + + UsbConnector + 0 + port + + BwAAAA== + + + HS08 + + UsbConnector + 0 + port + + CAAAAA== + + + HS09 + + #port + + CQAAAA== + + UsbConnector + 3 + + HS10 + + #port + + CgAAAA== + + UsbConnector + 3 + + HS11 + + #port + + CwAAAA== + + UsbConnector + 3 + + HS12 + + #port + + DAAAAA== + + UsbConnector + 3 + + SS01 + + UsbConnector + 3 + port + + DQAAAA== + + + SS02 + + #port + + DgAAAA== + + UsbConnector + 3 + + SS03 + + #port + + DwAAAA== + + UsbConnector + 3 + + SS04 + + #port + + EAAAAA== + + UsbConnector + 3 + + + + model + iMacPro1,1 + + + OSBundleRequired + Root + + diff --git a/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist b/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist new file mode 100644 index 0000000..1cfc5d5 --- /dev/null +++ b/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist @@ -0,0 +1,72 @@ + + + + + BuildMachineOSBuild + 18G95 + CFBundleDevelopmentRegion + en + CFBundleExecutable + USBWakeFixup + CFBundleIdentifier + com.osy86.USBWakeFixup + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + USBWakeFixup + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 10G8 + DTPlatformVersion + GM + DTSDKBuild + 18G74 + DTSDKName + macosx10.14 + DTXcode + 1030 + DTXcodeBuild + 10G8 + IOKitPersonalities + + Fake XHCI + + CFBundleIdentifier + com.osy86.USBWakeFixup + IOClass + USBWakeFixup + IONameMatch + PNP0D10 + IOPropertyMatch + + _UID + WAKE + + IOProviderClass + IOACPIPlatformDevice + + + NSHumanReadableCopyright + Copyright © 2019 osy86. All rights reserved. + OSBundleLibraries + + com.apple.iokit.IOACPIFamily + 1.0d1 + com.apple.kpi.iokit + 7.0 + com.apple.kpi.libkern + 8.0d0 + + + diff --git a/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup b/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup new file mode 100644 index 0000000..7191cd3 Binary files /dev/null and b/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup differ diff --git a/OC/config.plist b/OC/config.plist index 20da3bf..d99d090 100644 --- a/OC/config.plist +++ b/OC/config.plist @@ -8,7 +8,7 @@ Comment - Read the comment in dsl sample + SSDT-AWAC.aml Enabled Path @@ -16,15 +16,31 @@ Comment - Read the comment in dsl sample + SSDT-EC.aml Enabled Path - SSDT-EC-USBX-DESKTOP.aml + SSDT-EC.aml Comment - Read the comment in dsl sample + SSDT-GPRW.aml + Enabled + + Path + SSDT-GPRW.aml + + + Comment + SSDT-HPET.aml + Enabled + + Path + SSDT-HPET.aml + + + Comment + SSDT-PLUG-ALT.aml Enabled Path @@ -32,17 +48,214 @@ Comment - Read the comment in dsl sample + SSDT-SBUS-MCHC.aml Enabled Path - SSDT-RHUB.aml + SSDT-SBUS-MCHC.aml + + + Comment + SSDT-USBW.aml + Enabled + + Path + SSDT-USBW.aml + + + Comment + SSDT-USBX.aml + Enabled + + Path + SSDT-USBX.aml Delete Patch - + + + Base + + BaseSkip + 0 + Comment + HPET _STA to XSTA Rename + Count + 0 + Enabled + + Find + EV9TVEE= + Limit + 0 + Mask + + OemTableId + AAAAAA== + Replace + EVhTVEE= + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + AAAAAA== + + + Base + + BaseSkip + 0 + Comment + HPET _CRS to XCRS Rename + Count + 0 + Enabled + + Find + JV9DUlM= + Limit + 0 + Mask + + OemTableId + AAAAAA== + Replace + JVhDUlM= + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + AAAAAA== + + + Base + + BaseSkip + 0 + Comment + IPIC IRQ 2 Patch + Count + 0 + Enabled + + Find + IgQAeQA= + Limit + 0 + Mask + + OemTableId + AAAAAA== + Replace + IgAAeQA= + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + AAAAAA== + + + Base + + BaseSkip + 0 + Comment + RTC IRQ 8 Patch + Count + 0 + Enabled + + Find + IgABeQA= + Limit + 0 + Mask + + OemTableId + AAAAAA== + Replace + IgAAeQA= + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + AAAAAA== + + + Base + + BaseSkip + 0 + Comment + TIMR IRQ 0 Patch + Count + 0 + Enabled + + Find + IgEAeQA= + Limit + 0 + Mask + + OemTableId + AAAAAA== + Replace + IgAAeQA= + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + AAAAAA== + + + Base + + BaseSkip + 0 + Comment + change Method(GPRW,2,N) to XPRW, pair with SSDT-GPRW.aml + Count + 0 + Enabled + + Find + R1BSVw== + Limit + 0 + Mask + + OemTableId + + Replace + WFBSVw== + ReplaceMask + + Skip + 0 + TableLength + 0 + TableSignature + + + Quirks FadtEnableReset @@ -113,23 +326,12 @@ Add - # PciRoot(0x0)/Pci(0x1B,0x2)/Pci(0x0,0x0) + PciRoot(0x0)/Pci(0x1F,0x3) - device-id - 8hUAAA== - device_type - Ethernet Controller + layout-id + 66 model - Intel(R) Ethernet Controller i225-LM - - # PciRoot(0x0)/Pci(0x1B,0x3)/Pci(0x0,0x0) - - device-id - 8hUAAA== - device_type - Ethernet Controller - model - Intel(R) Ethernet Controller i225-LM + Realtek ALC897 Delete @@ -337,6 +539,42 @@ PlistPath Contents/Info.plist + + Arch + x86_64 + BundlePath + USBMap.kext + Comment + + Enabled + + ExecutablePath + + MaxKernel + + MinKernel + + PlistPath + Contents/Info.plist + + + Arch + Any + BundlePath + USBWakeFixup.kext + Comment + USBWakeFixup.kext + Enabled + + ExecutablePath + Contents/MacOS/USBWakeFixup + MaxKernel + + MinKernel + + PlistPath + Contents/Info.plist + Block @@ -474,7 +712,7 @@ PickerAudioAssist PickerMode - External + Builtin PickerVariant Auto PollAppleHotKeys @@ -642,7 +880,7 @@ MaxBIOSVersion ProcessorType - 0 + 3841 ROM 8LR5Nk5V SpoofVendor diff --git a/Utils/macrecovery/README.md b/Utils/macrecovery/README.md deleted file mode 100644 index 4cf122b..0000000 --- a/Utils/macrecovery/README.md +++ /dev/null @@ -1,8 +0,0 @@ -## macrecovery - -macrecovery is a tool that helps to automate recovery interaction. It can be used to download diagnostics and recovery as well as analyse MLB. - -Requires python3 to run. Run with `-h` argument to see all available arguments. - -To create a disk image for a virtual machine installation use `build-image.sh`. - diff --git a/Utils/macrecovery/boards.json b/Utils/macrecovery/boards.json deleted file mode 100644 index 489daa3..0000000 --- a/Utils/macrecovery/boards.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "Mac-EE2EBD4B90B839A8": "13.4", - "Mac-BE0E8AC46FE800CC": "11.7.7", - "Mac-9AE82516C7C6B903": "12.6.6", - "Mac-942452F5819B1C1B": "10.13.6", - "Mac-942C5DF58193131B": "10.13.6", - "Mac-C08A6BB70A942AC2": "10.13.6", - "Mac-742912EFDBEE19B3": "10.13.6", - "Mac-66F35F19FE2A0D05": "10.15.7", - "Mac-2E6FAB96566FE58C": "10.15.7", - "Mac-35C1E88140C3E6CF": "11.7.7", - "Mac-7DF21CB3ED6977E5": "11.7.7", - "Mac-9F18E312C5C2BF0B": "12.6.6", - "Mac-937CB26E2E02BB01": "12.6.6", - "Mac-827FAC58A8FDFA22": "latest", - "Mac-226CB3C6A851A671": "latest", - "Mac-0CFF9C7C2B63DF8D": "latest", - "Mac-C3EC7CD22292981F": "10.15.7", - "Mac-AFD8A9D944EA4843": "10.15.7", - "Mac-189A3D4F975D5FFC": "11.7.7", - "Mac-3CBD00234E554E41": "11.7.7", - "Mac-2BD1B31983FE1663": "11.7.7", - "Mac-06F11FD93F0323C5": "12.6.6", - "Mac-06F11F11946D27C5": "12.6.6", - "Mac-E43C1C25D4880AD6": "12.6.6", - "Mac-473D31EABEB93F9B": "12.6.6", - "Mac-66E35819EE2D0D05": "12.6.6", - "Mac-A5C67F76ED83108C": "12.6.6", - "Mac-B4831CEBD52A0C4C": "13.4", - "Mac-CAD6701F7CEA0921": "13.4", - "Mac-551B86E5744E2388": "13.4", - "Mac-937A206F2EE63C01": "latest", - "Mac-827FB448E656EC26": "latest", - "Mac-1E7E29AD0135F9BC": "latest", - "Mac-53FDB3D8DB8CA971": "latest", - "Mac-E1008331FDC96864": "latest", - "Mac-5F9802EFE386AA28": "latest", - "Mac-E7203C0F68AA0004": "latest", - "Mac-A61BADE1FDAD7B05": "latest", - "Mac-F22589C8": "10.13.6", - "Mac-94245B3640C91C81": "10.13.6", - "Mac-94245A3940C91C80": "10.13.6", - "Mac-942459F5819B171B": "10.13.6", - "Mac-4B7AC7E43945597E": "10.15.7", - "Mac-6F01561E16C75D06": "10.15.7", - "Mac-F60DEB81FF30ACF6": "12.6.6", - "Mac-27AD2F918AE68F61": "latest", - "Mac-F2208EC8": "10.13.6", - "Mac-8ED6AF5B48C039E1": "10.13.6", - "Mac-4BC72D62AD45599E": "10.13.6", - "Mac-7BA5B2794B2CDB12": "10.13.6", - "Mac-031AEE4D24BFF0B1": "10.15.7", - "Mac-F65AE981FFA204ED": "10.15.7", - "Mac-35C5E08120C7EEAF": "12.6.6", - "Mac-7BA5B2DFE22DDD8C": "latest", - "Mac-942B5BF58194151B": "10.13.6", - "Mac-942B59F58194171B": "10.13.6", - "Mac-00BE6ED71E35EB86": "10.15.7", - "Mac-FC02E91DDD3FA6A4": "10.15.7", - "Mac-7DF2A3B5E5D671ED": "10.15.7", - "Mac-031B6874CF7F642A": "10.15.7", - "Mac-27ADBB7B4CEE8E61": "10.15.7", - "Mac-77EB7D7DAF985301": "10.15.7", - "Mac-81E3E92DD6088272": "11.7.7", - "Mac-42FD25EABCABB274": "11.7.7", - "Mac-A369DDC4E67F1C45": "12.6.6", - "Mac-FFE5EF870D7BA81A": "12.6.6", - "Mac-DB15BD556843C820": "12.6.6", - "Mac-65CE76090165799A": "12.6.6", - "Mac-B809C3757DA9BB8D": "12.6.6", - "Mac-4B682C642B45593E": "13.4", - "Mac-77F17D7DA9285301": "13.4", - "Mac-BE088AF8C5EB4FA2": "13.4", - "Mac-AA95B1DDAB278B95": "latest", - "Mac-63001698E7A34814": "latest", - "Mac-CFF7D910A743CAAF": "latest", - "Mac-AF89B6D9451A490B": "latest", - "Mac-7BA5B2D9E42DDD94": "latest" -} \ No newline at end of file diff --git a/Utils/macrecovery/build-image.sh b/Utils/macrecovery/build-image.sh deleted file mode 100755 index 8dc7107..0000000 --- a/Utils/macrecovery/build-image.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -e - -rm -rf Recovery.RO.dmg Recovery.RO.raw Recovery.dmg.sparseimage -hdiutil create -size 800m -layout "UNIVERSAL HD" -type SPARSE -o Recovery.dmg -newDevice=$(hdiutil attach -nomount Recovery.dmg.sparseimage | head -n 1 | awk '{print $1}') -echo newdevice "$newDevice" -diskutil partitionDisk "${newDevice}" 1 MBR fat32 RECOVERY R -N=$(echo "$newDevice" | tr -dc '0-9') -diskutil mount disk"${N}"s1 -MOUNT="$(diskutil info disk"${N}"s1 | sed -n 's/.*Mount Point: *//p')" -mkdir -p "$MOUNT/com.apple.recovery.boot" -cp ./*.dmg ./*.chunklist "$MOUNT/com.apple.recovery.boot/" -diskutil umount disk"${N}"s1 -hdiutil detach "$newDevice" -hdiutil convert -format UDZO Recovery.dmg.sparseimage -o Recovery.RO.dmg -rm Recovery.dmg.sparseimage -qemu-img convert -f dmg -O raw Recovery.RO.dmg Recovery.raw -rm Recovery.RO.dmg diff --git a/Utils/macrecovery/download-macOS-Big-Sur.cmd b/Utils/macrecovery/download-macOS-Big-Sur.cmd deleted file mode 100755 index 20c9bb2..0000000 --- a/Utils/macrecovery/download-macOS-Big-Sur.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -rem Download imagem Recovery macOS Big Sur -rem -rem Gabriel Luchina -rem Universo Hackintosh -rem https://universohackintosh.com.br - -cls - -python ./macrecovery.py -b Mac-42FD25EABCABB274 -m 00000000000000000 download diff --git a/Utils/macrecovery/download-macOS-Catalina.cmd b/Utils/macrecovery/download-macOS-Catalina.cmd deleted file mode 100755 index 17c7679..0000000 --- a/Utils/macrecovery/download-macOS-Catalina.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -rem Download imagem Recovery macOS Catalina -rem -rem Gabriel Luchina -rem Universo Hackintosh -rem https://universohackintosh.com.br - -cls - -python ./macrecovery.py -b Mac-00BE6ED71E35EB86 -m 00000000000000000 download diff --git a/Utils/macrecovery/download-macOS-Monterey.cmd b/Utils/macrecovery/download-macOS-Monterey.cmd deleted file mode 100755 index fc3442b..0000000 --- a/Utils/macrecovery/download-macOS-Monterey.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -rem Download imagem Recovery macOS Monterey -rem -rem Gabriel Luchina -rem Universo Hackintosh -rem https://universohackintosh.com.br - -cls - -python ./macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000000000 download diff --git a/Utils/macrecovery/download-macOS-Ventura.cmd b/Utils/macrecovery/download-macOS-Ventura.cmd deleted file mode 100755 index cf17110..0000000 --- a/Utils/macrecovery/download-macOS-Ventura.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -rem Download imagem Recovery macOS Ventura -rem -rem Gabriel Luchina -rem Universo Hackintosh -rem https://universohackintosh.com.br - -cls - -python ./macrecovery.py -b Mac-B4831CEBD52A0C4C -m 00000000000000000 download diff --git a/Utils/macrecovery/macrecovery.py b/Utils/macrecovery/macrecovery.py deleted file mode 100755 index 76a60aa..0000000 --- a/Utils/macrecovery/macrecovery.py +++ /dev/null @@ -1,502 +0,0 @@ -#!/usr/bin/env python3 - -""" -Gather recovery information for Macs. - -Copyright (c) 2019, vit9696 -""" - -import argparse -import binascii -import hashlib -import json -import linecache -import os -import random -import struct -import sys - -try: - from urllib.request import Request, HTTPError, urlopen - from urllib.parse import urlparse -except ImportError: - from urllib2 import Request, HTTPError, urlopen - from urlparse import urlparse - -SELF_DIR = os.path.dirname(os.path.realpath(__file__)) - -RECENT_MAC = 'Mac-7BA5B2D9E42DDD94' -MLB_ZERO = '00000000000000000' -MLB_VALID = 'C02749200YGJ803AX' -MLB_PRODUCT = '00000000000J80300' - -TYPE_SID = 16 -TYPE_K = 64 -TYPE_FG = 64 - -INFO_PRODUCT = 'AP' -INFO_IMAGE_LINK = 'AU' -INFO_IMAGE_HASH = 'AH' -INFO_IMAGE_SESS = 'AT' -INFO_SIGN_LINK = 'CU' -INFO_SIGN_HASH = 'CH' -INFO_SIGN_SESS = 'CT' -INFO_REQURED = [INFO_PRODUCT, INFO_IMAGE_LINK, INFO_IMAGE_HASH, INFO_IMAGE_SESS, INFO_SIGN_LINK, INFO_SIGN_HASH, INFO_SIGN_SESS] - - -def run_query(url, headers, post=None, raw=False): - if post is not None: - data = '\n'.join([entry + '=' + post[entry] for entry in post]) - if sys.version_info[0] >= 3: - data = data.encode('utf-8') - else: - data = None - req = Request(url=url, headers=headers, data=data) - try: - response = urlopen(req) - if raw: - return response - return dict(response.info()), response.read() - except HTTPError as e: - print(f'ERROR: "{e}" when connecting to {url}') - sys.exit(1) - - -def generate_id(id_type, id_value=None): - valid_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'] - return ''.join(random.choice(valid_chars) for i in range(id_type)) if not id_value else id_value - - -def product_mlb(mlb): - return '00000000000' + mlb[11] + mlb[12] + mlb[13] + mlb[14] + '00' - - -def mlb_from_eeee(eeee): - if len(eeee) != 4: - print('ERROR: Invalid EEEE code length!') - sys.exit(1) - - return f'00000000000{eeee}00' - - -def int_from_unsigned_bytes(byte_list, byteorder): - if byteorder == 'little': - byte_list = byte_list[::-1] - encoded = binascii.hexlify(byte_list) - return int(encoded, 16) - - -# zhangyoufu https://gist.github.com/MCJack123/943eaca762730ca4b7ae460b731b68e7#gistcomment-3061078 2021-10-08 -Apple_EFI_ROM_public_key_1 = 0xC3E748CAD9CD384329E10E25A91E43E1A762FF529ADE578C935BDDF9B13F2179D4855E6FC89E9E29CA12517D17DFA1EDCE0BEBF0EA7B461FFE61D94E2BDF72C196F89ACD3536B644064014DAE25A15DB6BB0852ECBD120916318D1CCDEA3C84C92ED743FC176D0BACA920D3FCF3158AFF731F88CE0623182A8ED67E650515F75745909F07D415F55FC15A35654D118C55A462D37A3ACDA08612F3F3F6571761EFCCBCC299AEE99B3A4FD6212CCFFF5EF37A2C334E871191F7E1C31960E010A54E86FA3F62E6D6905E1CD57732410A3EB0C6B4DEFDABE9F59BF1618758C751CD56CEF851D1C0EAA1C558E37AC108DA9089863D20E2E7E4BF475EC66FE6B3EFDCF - -ChunkListHeader = struct.Struct('<4sIBBBxQQQ') -assert ChunkListHeader.size == 0x24 - -Chunk = struct.Struct(' 0 - assert chunk_offset == 0x24 - assert signature_offset == chunk_offset + Chunk.size * chunk_count - for _ in range(chunk_count): - data = f.read(Chunk.size) - hash_ctx.update(data) - chunk_size, chunk_sha256 = Chunk.unpack(data) - yield chunk_size, chunk_sha256 - digest = hash_ctx.digest() - if signature_method == 1: - data = f.read(256) - assert len(data) == 256 - signature = int_from_unsigned_bytes(data, 'little') - plaintext = 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200000000000000000000000000000000000000000000000000000000000000000 | int_from_unsigned_bytes(digest, 'big') - assert pow(signature, 0x10001, Apple_EFI_ROM_public_key_1) == plaintext - elif signature_method == 2: - data = f.read(32) - assert data == digest - raise RuntimeError('Chunklist missing digital signature') - else: - raise NotImplementedError - assert f.read(1) == b'' - - -def get_session(args): - headers = { - 'Host': 'osrecovery.apple.com', - 'Connection': 'close', - 'User-Agent': 'InternetRecovery/1.0', - } - - headers, _ = run_query('http://osrecovery.apple.com/', headers) - - if args.verbose: - print('Session headers:') - for header in headers: - print(f'{header}: {headers[header]}') - - for header in headers: - if header.lower() == 'set-cookie': - cookies = headers[header].split('; ') - for cookie in cookies: - return cookie if cookie.startswith('session=') else ... - - raise RuntimeError('No session in headers ' + str(headers)) - - -def get_image_info(session, bid, mlb=MLB_ZERO, diag=False, os_type='default', cid=None): - headers = { - 'Host': 'osrecovery.apple.com', - 'Connection': 'close', - 'User-Agent': 'InternetRecovery/1.0', - 'Cookie': session, - 'Content-Type': 'text/plain', - } - - post = { - 'cid': generate_id(TYPE_SID, cid), - 'sn': mlb, - 'bid': bid, - 'k': generate_id(TYPE_K), - 'fg': generate_id(TYPE_FG) - } - - if diag: - url = 'http://osrecovery.apple.com/InstallationPayload/Diagnostics' - else: - url = 'http://osrecovery.apple.com/InstallationPayload/RecoveryImage' - post['os'] = os_type - - headers, output = run_query(url, headers, post) - - output = output.decode('utf-8') - info = {} - for line in output.split('\n'): - try: - key, value = line.split(': ') - info[key] = value - except Exception: - continue - - for k in INFO_REQURED: - if k not in info: - raise RuntimeError(f'Missing key {k}') - - return info - - -def save_image(url, sess, filename='', directory=''): - purl = urlparse(url) - headers = { - 'Host': purl.hostname, - 'Connection': 'close', - 'User-Agent': 'InternetRecovery/1.0', - 'Cookie': '='.join(['AssetToken', sess]) - } - - if not os.path.exists(directory): - os.mkdir(directory) - - if filename == '': - filename = os.path.basename(purl.path) - if filename.find('/') >= 0 or filename == '': - raise RuntimeError('Invalid save path ' + filename) - - print(f'Saving {url} to {directory}/{filename}...') - - with open(os.path.join(directory, filename), 'wb') as fh: - response = run_query(url, headers, raw=True) - size = 0 - while True: - chunk = response.read(2**20) - if not chunk: - break - fh.write(chunk) - size += len(chunk) - print(f'\r{size / (2**20)} MBs downloaded...', end='') - sys.stdout.flush() - print('\rDownload complete!\t\t\t\t\t') - - return os.path.join(directory, os.path.basename(filename)) - - -def verify_image(dmgpath, cnkpath): - print('Verifying image with chunklist...') - - with open(dmgpath, 'rb') as dmgf: - cnkcount = 0 - for cnksize, cnkhash in verify_chunklist(cnkpath): - cnkcount += 1 - print(f'\rChunk {cnkcount} ({cnksize} bytes)', end='') - sys.stdout.flush() - cnk = dmgf.read(cnksize) - if len(cnk) != cnksize: - raise RuntimeError(f'Invalid chunk {cnkcount} size: expected {cnksize}, read {len(cnk)}') - if hashlib.sha256(cnk).digest() != cnkhash: - raise RuntimeError(f'Invalid chunk {cnkcount}: hash mismatch') - if dmgf.read(1) != b'': - raise RuntimeError('Invalid image: larger than chunklist') - print('\rImage verification complete!\t\t\t\t\t') - - -def action_download(args): - """ - Reference information for queries: - - Recovery latest: - cid=3076CE439155BA14 - sn=... - bid=Mac-E43C1C25D4880AD6 - k=4BE523BB136EB12B1758C70DB43BDD485EBCB6A457854245F9E9FF0587FB790C - os=latest - fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC - - Recovery default: - cid=4A35CB95FF396EE7 - sn=... - bid=Mac-E43C1C25D4880AD6 - k=0A385E6FFC3DDD990A8A1F4EC8B98C92CA5E19C9FF1DD26508C54936D8523121 - os=default - fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC - - Diagnostics: - cid=050C59B51497CEC8 - sn=... - bid=Mac-E43C1C25D4880AD6 - k=37D42A8282FE04A12A7D946304F403E56A2155B9622B385F3EB959A2FBAB8C93 - fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC - """ - - session = get_session(args) - info = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=args.diagnostics, os_type=args.os_type) - if args.verbose: - print(info) - print(f'Downloading {info[INFO_PRODUCT]}...') - dmgname = '' if args.basename == '' else args.basename + '.dmg' - dmgpath = save_image(info[INFO_IMAGE_LINK], info[INFO_IMAGE_SESS], dmgname, args.outdir) - cnkname = '' if args.basename == '' else args.basename + '.chunklist' - cnkpath = save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir) - try: - verify_image(dmgpath, cnkpath) - return 0 - except Exception as err: - if isinstance(err, AssertionError) and str(err) == '': - try: - tb = sys.exc_info()[2] - while tb.tb_next: - tb = tb.tb_next - err = linecache.getline(tb.tb_frame.f_code.co_filename, tb.tb_lineno, tb.tb_frame.f_globals).strip() - except Exception: - err = "Invalid chunklist" - print(f'\rImage verification failed. ({err})') - return 1 - - -def action_selfcheck(args): - """ - Sanity check server logic for recovery: - - if not valid(bid): - return error() - ppp = get_ppp(sn) - if not valid(ppp): - return latest_recovery(bid = bid) # Returns newest for bid. - if valid(sn): - if os == 'default': - return default_recovery(sn = sn, ppp = ppp) # Returns oldest for sn. - else: - return latest_recovery(sn = sn, ppp = ppp) # Returns newest for sn. - return default_recovery(ppp = ppp) # Returns oldest. - """ - - session = get_session(args) - valid_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_VALID, diag=False, os_type='default') - valid_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_VALID, diag=False, os_type='latest') - product_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_PRODUCT, diag=False, os_type='default') - product_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_PRODUCT, diag=False, os_type='latest') - generic_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='default') - generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest') - - if args.verbose: - print(valid_default) - print(valid_latest) - print(product_default) - print(product_latest) - print(generic_default) - print(generic_latest) - - if valid_default[INFO_PRODUCT] == valid_latest[INFO_PRODUCT]: - # Valid MLB must give different default and latest if this is not a too new product. - print(f'ERROR: Cannot determine any previous product, got {valid_default[INFO_PRODUCT]}') - return 1 - - if product_default[INFO_PRODUCT] != product_latest[INFO_PRODUCT]: - # Product-only MLB must give the same value for default and latest. - print(f'ERROR: Latest and default do not match for product MLB, got {product_default[INFO_PRODUCT]} and {product_latest[INFO_PRODUCT]}') - return 1 - - if generic_default[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]: - # Zero MLB always give the same value for default and latest. - print(f'ERROR: Generic MLB gives different product, got {generic_default[INFO_PRODUCT]} and {generic_latest[INFO_PRODUCT]}') - return 1 - - if valid_latest[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]: - # Valid MLB must always equal generic MLB. - print(f'ERROR: Cannot determine unified latest product, got {valid_latest[INFO_PRODUCT]} and {generic_latest[INFO_PRODUCT]}') - return 1 - - if product_default[INFO_PRODUCT] != valid_default[INFO_PRODUCT]: - # Product-only MLB can give the same value with valid default MLB. - # This is not an error for all models, but for our chosen code it is. - print('ERROR: Valid and product MLB give mismatch, got {product_default[INFO_PRODUCT]} and {valid_default[INFO_PRODUCT]}') - return 1 - - print('SUCCESS: Found no discrepancies with MLB validation algorithm!') - return 0 - - -def action_verify(args): - """ - Try to verify MLB serial number. - """ - session = get_session(args) - generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest') - uvalid_default = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=False, os_type='default') - uvalid_latest = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=False, os_type='latest') - uproduct_default = get_image_info(session, bid=args.board_id, mlb=product_mlb(args.mlb), diag=False, os_type='default') - - if args.verbose: - print(generic_latest) - print(uvalid_default) - print(uvalid_latest) - print(uproduct_default) - - # Verify our MLB number. - if uvalid_default[INFO_PRODUCT] != uvalid_latest[INFO_PRODUCT]: - print(f'SUCCESS: {args.mlb} MLB looks valid and supported!' if uvalid_latest[INFO_PRODUCT] == generic_latest[INFO_PRODUCT] else f'SUCCESS: {args.mlb} MLB looks valid, but probably unsupported!') - return 0 - - print('UNKNOWN: Run selfcheck, check your board-id, or try again later!') - - # Here we have matching default and latest products. This can only be true for very - # new models. These models get either latest or special builds. - if uvalid_default[INFO_PRODUCT] == generic_latest[INFO_PRODUCT]: - print(f'UNKNOWN: {args.mlb} MLB can be valid if very new!') - return 0 - if uproduct_default[INFO_PRODUCT] != uvalid_default[INFO_PRODUCT]: - print(f'UNKNOWN: {args.mlb} MLB looks invalid, other models use product {uproduct_default[INFO_PRODUCT]} instead of {uvalid_default[INFO_PRODUCT]}!') - return 0 - print(f'UNKNOWN: {args.mlb} MLB can be valid if very new and using special builds!') - return 0 - - -def action_guess(args): - """ - Attempt to guess which model does this MLB belong. - """ - - mlb = args.mlb - anon = mlb.startswith('000') - - with open(args.board_db, 'r', encoding='utf-8') as fh: - db = json.load(fh) - - supported = {} - - session = get_session(args) - - generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest') - - for model in db: - try: - if anon: - # For anonymous lookup check when given model does not match latest. - model_latest = get_image_info(session, bid=model, mlb=MLB_ZERO, diag=False, os_type='latest') - - if model_latest[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]: - if db[model] == 'current': - print(f'WARN: Skipped {model} due to using latest product {model_latest[INFO_PRODUCT]} instead of {generic_latest[INFO_PRODUCT]}') - continue - - user_default = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='default') - - if user_default[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]: - supported[model] = [db[model], user_default[INFO_PRODUCT], generic_latest[INFO_PRODUCT]] - else: - # For normal lookup check when given model has mismatching normal and latest. - user_latest = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='latest') - - user_default = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='default') - - if user_latest[INFO_PRODUCT] != user_default[INFO_PRODUCT]: - supported[model] = [db[model], user_default[INFO_PRODUCT], user_latest[INFO_PRODUCT]] - - except Exception as e: - print(f'WARN: Failed to check {model}, exception: {e}') - - if len(supported) > 0: - print(f'SUCCESS: MLB {mlb} looks supported for:') - for model in supported.items(): - print(f'- {model}, up to {supported[model][0]}, default: {supported[model][1]}, latest: {supported[model][2]}') - return 0 - - print(f'UNKNOWN: Failed to determine supported models for MLB {mlb}!') - return None - - -def main(): - parser = argparse.ArgumentParser(description='Gather recovery information for Macs') - parser.add_argument('action', choices=['download', 'selfcheck', 'verify', 'guess'], - help='Action to perform: "download" - performs recovery downloading,' - ' "selfcheck" checks whether MLB serial validation is possible, "verify" performs' - ' MLB serial verification, "guess" tries to find suitable mac model for MLB.') - parser.add_argument('-o', '--outdir', type=str, default='com.apple.recovery.boot', - help='customise output directory for downloading, defaults to com.apple.recovery.boot') - parser.add_argument('-n', '--basename', type=str, default='', - help='customise base name for downloading, defaults to remote name') - parser.add_argument('-b', '--board-id', type=str, default=RECENT_MAC, - help=f'use specified board identifier for downloading, defaults to {RECENT_MAC}') - parser.add_argument('-m', '--mlb', type=str, default=MLB_ZERO, - help=f'use specified logic board serial for downloading, defaults to {MLB_ZERO}') - parser.add_argument('-e', '--code', type=str, default='', - help='generate product logic board serial with specified product EEEE code') - parser.add_argument('-os', '--os-type', type=str, default='default', choices=['default', 'latest'], - help=f'use specified os type, defaults to default {MLB_ZERO}') - parser.add_argument('-diag', '--diagnostics', action='store_true', help='download diagnostics image') - parser.add_argument('-v', '--verbose', action='store_true', help='print debug information') - parser.add_argument('-db', '--board-db', type=str, default=os.path.join(SELF_DIR, 'boards.json'), - help='use custom board list for checking, defaults to boards.json') - - args = parser.parse_args() - - if args.code != '': - args.mlb = mlb_from_eeee(args.code) - - if len(args.mlb) != 17: - print('ERROR: Cannot use MLBs in non 17 character format!') - sys.exit(1) - - if args.action == 'download': - return action_download(args) - if args.action == 'selfcheck': - return action_selfcheck(args) - if args.action == 'verify': - return action_verify(args) - if args.action == 'guess': - return action_guess(args) - - assert False - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/Utils/macrecovery/recovery_urls.txt b/Utils/macrecovery/recovery_urls.txt deleted file mode 100644 index ca233f3..0000000 --- a/Utils/macrecovery/recovery_urls.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Lion (10.7): -python macrecovery.py -b Mac-2E6FAB96566FE58C -m 00000000000F25Y00 download -python macrecovery.py -b Mac-C3EC7CD22292981F -m 00000000000F0HM00 download - -# Mountain Lion (10.8): -python macrecovery.py -b Mac-7DF2A3B5E5D671ED -m 00000000000F65100 download - -# Mavericks (10.9): -python macrecovery.py -b Mac-F60DEB81FF30ACF6 -m 00000000000FNN100 download - -# Yosemite (10.10): -python macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000GDVW00 download - -# El Capitan (10.11): -python macrecovery.py -b Mac-FFE5EF870D7BA81A -m 00000000000GQRX00 download - -# Sierra (10.12): -python macrecovery.py -b Mac-77F17D7DA9285301 -m 00000000000J0DX00 download - -# High Sierra (10.13) -python macrecovery.py -b Mac-7BA5B2D9E42DDD94 -m 00000000000J80300 download -python macrecovery.py -b Mac-BE088AF8C5EB4FA2 -m 00000000000J80300 download - -# Mojave (10.14) -python macrecovery.py -b Mac-7BA5B2DFE22DDD8C -m 00000000000KXPG00 download - -# Catalina (10.15) -python macrecovery.py -b Mac-00BE6ED71E35EB86 -m 00000000000000000 download - -# Big Sur (11) -python macrecovery.py -b Mac-42FD25EABCABB274 -m 00000000000000000 download - -# Monterey (12) -python macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000000000 download - -# Latest version -# ie. Ventura (13) -python macrecovery.py -b Mac-B4831CEBD52A0C4C -m 00000000000000000 download diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist b/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist deleted file mode 100644 index 9c7abaa..0000000 --- a/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - NSServices - - - NSBackgroundColorName - background - NSIconName - NSTouchBarTransferDownload - NSMenuItem - - default - Mount EFI - - NSMessage - runWorkflowAsService - NSSendFileTypes - - public.folder - - - - - diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png b/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png deleted file mode 100644 index 7fd8cb5..0000000 Binary files a/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png and /dev/null differ diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py deleted file mode 100755 index 3a8d621..0000000 --- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py +++ /dev/null @@ -1,411 +0,0 @@ -import os, sys -sys.path.append(os.path.abspath(os.path.dirname(os.path.realpath(__file__)))) -import run, plist - -class Disk: - def __init__(self): - self.r = run.Run() - self.diskdump = self.check_diskdump() - self.full_os_version = self.r.run({"args":["sw_vers", "-productVersion"]})[0] - if len(self.full_os_version.split(".")) < 3: - # Ensure the format is XX.YY.ZZ - self.full_os_version += ".0" - self.os_version = ".".join(self.full_os_version.split(".")[:2]) - self.sudo_mount_version = "10.13.6" - self.efi_guids = ["C12A7328-F81F-11D2-BA4B-00A0C93EC93B"] - self.disks = self.get_disks() - - def check_diskdump(self): - ddpath = os.path.join(os.path.dirname(os.path.realpath(__file__)),"diskdump") - if not os.path.exists(ddpath): - raise FileNotFoundError("Could not locate diskdump") - if "com.apple.quarantine" in self.r.run({"args":["xattr",ddpath]})[0]: - self.r.run({"args":["xattr","-d","com.apple.quarantine",ddpath]}) - return ddpath - - def update(self): - # Refresh our disk list - self.disks = self.get_disks() - return self.disks - - def get_disks(self): - # Check for our binary - and ensure it's setup to run - ddpath = os.path.join(os.path.dirname(os.path.realpath(__file__)),"diskdump") - if not os.path.exists(ddpath): return {} - # Get our "diskutil list" and diskdump info. Run diskutil list first - # as it takes longer - but will stall while waiting for disks to appear, - # meaning our diskdump output will be better reflected. - diskutil_list = self.r.run({"args":["diskutil","list"]})[0] - diskstring = self.r.run({"args":[ddpath]})[0] - if not diskstring: return {} - diskdump = plist.loads(diskstring) - last_disk = None - for line in diskutil_list.split("\n"): - if line.startswith("/dev/disk"): - last_disk = line.split()[0].split("/")[-1] - elif not last_disk: - continue - elif line.strip().startswith("Logical Volume on"): - # Core Storage - ps = line.split("Logical Volume on")[1].strip().split(", ") - disk = self.get_disk(last_disk,disk_dict=diskdump) - if disk: # Update parent disk - disk["container"] = True - disk["core_storage"] = True - disk["physical_stores"] = ps - # Save a reference to the physical stores - for s in ps: - store = self.get_disk(s,disk_dict=diskdump) - if store: - store["container_for"] = last_disk - store["core_storage_container_for"] = last_disk - elif line.strip().startswith("Physical Store"): - # APFS - ps = line.split("Physical Store")[1].strip().split(", ") - disk = self.get_disk(last_disk,disk_dict=diskdump) - if disk: # Update parent disk - disk["container"] = True - disk["apfs"] = True - disk["physical_stores"] = ps - # Save a reference to the physical stores - for s in ps: - store = self.get_disk(s,disk_dict=diskdump) - if store: - store["container_for"] = last_disk - store["apfs_container_for"] = last_disk - return diskdump - - def get_identifier(self, disk = None, disk_dict = None): - # Should be able to take a mount point, disk name, or disk identifier, - # and return the disk's identifier - if isinstance(disk,dict): disk = disk.get("DAMediaBSDName") - if not disk: return - disk_dict = disk_dict or self.disks # Normalize the dict - disk = disk[6:] if disk.lower().startswith("/dev/rdisk") else disk[5:] if disk.lower().startswith("/dev/disk") else disk - if disk.lower() in disk_dict.get("AllDisks",[]): return disk - for d in disk_dict.get("AllDisksAndPartitions", []): - # Check the parent disk - if any((disk.lower()==d.get(x,"").lower() for x in ("DAMediaBSDName","DAVolumeName","DAVolumeUUID","DAMediaUUID","DAVolumePath"))): - return d.get("DAMediaBSDName") - # Check the partitions - for p in d.get("Partitions", []): - if any((disk.lower()==p.get(x,"").lower() for x in ("DAMediaBSDName","DAVolumeName","DAVolumeUUID","DAMediaUUID","DAVolumePath"))): - return p.get("DAMediaBSDName") - # At this point, we didn't find it - return None - - def get_parent(self, disk = None, disk_dict = None): - # For backward compatibility with the old disk.py approach - return self.get_physical_parent_identifiers(disk,disk_dict=disk_dict) - - def get_parent_identifier(self, disk = None, disk_dict = None): - # Resolves the passed disk value and returns the parent disk/container. - # i.e. Passing disk5s2s1 would return disk5 - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - return "disk"+disk.lower().split("disk")[1].split("s")[0] - - def get_physical_parent_identifier(self, disk = None, disk_dict = None): - # Returns the first hit from get_physical_parent_identifiers() - return next(iter(self.get_physical_parent_identifiers(disk, disk_dict=disk_dict) or []), None) - - def get_physical_parent_identifiers(self, disk = None, disk_dict = None): - # Resolves the passed disk to the physical parent disk identifiers. Useful for APFS - # and Core Storage volumes which are logical - and can span multiple disks. - # If you have an APFS container on disk4 and its Physical Store lists - # disk2s2, disk3s2 - this would return [disk2, disk3] - return [self.get_identifier(x,disk_dict=disk_dict) for x in self.get_physical_parent_disks(disk,disk_dict=disk_dict)] - - def get_physical_parent_disks(self, disk = None, disk_dict = None): - # Resolves the passed disk to the physical parent disk dicts. Useful for APFS - # and Core Storage volumes which are logcial and can span multiple physical - # disks. If you have an APFS container on disk4 and its Physical Store is on - # disk2s2 and disk3s2 - this would return the disk dicts for disk2 and disk3. - parent = self.get_parent_disk(disk, disk_dict=disk_dict) - if not parent: return [] - if not "physical_stores" in parent: return [parent] - return [self.get_parent_disk(x,disk_dict=disk_dict) for x in parent.get("physical_stores",[])] - - def get_parent_disk(self, disk = None, disk_dict = None): - # Returns the dict info for the parent of the passed mount point, name, identifier, etc - return self.get_disk(self.get_parent_identifier(disk,disk_dict=disk_dict),disk_dict=disk_dict) - - def get_disk(self, disk = None, disk_dict = None): - # Returns the dict info for the passed mount point, name, identifier, etc - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - parent = self.get_parent_identifier(disk,disk_dict=disk_dict) - # Walk AllDisksAndPartitions, and return the first hit - for d in (disk_dict or self.disks).get("AllDisksAndPartitions",[]): - d_ident = d.get("DAMediaBSDName") - if d_ident == disk: - return d # Got the disk - elif d_ident == parent: - # Got the parent - iterate the partitions - return next((p for p in d.get("Partitions",[]) if p.get("DAMediaBSDName")==disk),None) - return None # Didn't find it - - def get_efis(self, disk = None, disk_dict = None): - # Returns the identifiers for any EFI partitions attached to the - # parent disk(s) of the passed disk - efis = [] - for parent in self.get_physical_parent_identifiers(disk,disk_dict=disk_dict): - parent_dict = self.get_disk(parent,disk_dict=disk_dict) - if not parent_dict: continue - for part in parent_dict.get("Partitions",[]): - # Use the GUID instead of media name - as that can vary - if part.get("DAMediaContent","").upper() in self.efi_guids: - efis.append(part["DAMediaBSDName"]) - # Normalize case for the DAMediaName; - # macOS disks: "EFI System Partition", Windows disks: "EFI system partition" - # Maybe use this approach as a fallback at some point - but for now, just use the GUID - # if part.get("DAMediaName").lower() == "efi system partition": - # efis.append(part["DAMediaBSDName"]) - return efis - - def get_efi(self, disk = None, disk_dict = None): - # Returns the identifier for the first EFI partition found for - # the passed disk - return next(iter(self.get_efis(disk,disk_dict=disk_dict) or []), None) - - def get_mounted_volumes(self, disk_dict = None): - # Returns a list of mounted volumes - return (disk_dict or self.disks).get("MountPointsFromDisks",[]) - - def get_mounted_volume_dicts(self, disk_dict = None): - # Returns a list of dicts of name, identifier, mount point dicts - vol_list = [] - for v in (disk_dict or self.disks).get("MountPointsFromDisks"): - i = self.get_disk(v,disk_dict=disk_dict) - if not i: continue # Skip - as it didn't resolve - mount_point = self.get_mount_point(i,disk_dict=disk_dict) - # Check if we're either not mounted - or not mounted in /Volumes/ - if not v or not (v == "/" or v.lower().startswith("/volumes/")): - continue - vol = { - "name": self.get_volume_name(i,disk_dict=disk_dict), - "identifier": self.get_identifier(i,disk_dict=disk_dict), - "mount_point": v, - "disk_uuid": self.get_disk_uuid(i,disk_dict=disk_dict), - "volume_uuid": self.get_volume_uuid(i,disk_dict=disk_dict) - } - if "container_for" in i: vol["container_for"] = i["container_for"] - vol_list.append(vol) - return sorted(vol_list,key=lambda x:x["identifier"]) - - def get_disks_and_partitions_dict(self, disk_dict = None): - # Returns a list of dictionaries like so: - # { "disk0" : { - # "container": true/false, - # "physical_stores": [ - # "diskAsB", - # "diskXsY" - # ], - # "scheme": "Guid_partition_scheme", - # "partitions" : [ - # { - # "identifier" : "disk0s1", - # "name" : "EFI", - # "mount_point" : "/Volumes/EFI", - # "container_for": "diskCsD" - # } - # ] } } - disks = {} - for d in sorted((disk_dict or self.disks).get("AllDisksAndPartitions"),key=lambda x:x.get("DAMediaBSDName")): - if not "DAMediaBSDName" in d: continue # Malformed - parent = d["DAMediaBSDName"] - disks[parent] = {"partitions":[]} - # Save if the disk is logical - and a l)ist of its physical stores - for x in ("container","physical_stores"): - if x in d: disks[parent][x] = d[x] - disks[parent]["scheme"] = self.get_readable_partition_scheme(d,disk_dict=disk_dict) - # Check if this disk is also a volume - i.e. also a leaf, and insert it in the partitions list - partitions = d.get("Partitions",[]) - if d.get("DAMediaLeaf"): - partitions.insert(0,d) - for p in d.get("Partitions",[]): - part = { - "name": self.get_volume_name(p,disk_dict=disk_dict), - "identifier": self.get_identifier(p,disk_dict=disk_dict), - "mount_point": self.get_mount_point(p,disk_dict=disk_dict), - "disk_uuid": self.get_disk_uuid(p,disk_dict=disk_dict), - "volume_uuid": self.get_volume_uuid(p,disk_dict=disk_dict) - } - if "container_for" in p: part["container_for"] = p["container_for"] - disks[parent]["partitions"].append(part) - disks[parent]["partitions"].sort(key=lambda x:x["identifier"]) - return disks - - def _get_value(self, disk = None, value = None, disk_dict = None): - if not disk or not value: return # Missing info - if isinstance(disk,dict): return disk.get(value) - try: return self.get_disk(disk,disk_dict=disk_dict).get(value) - except: return - - def _is_uuid(self, value): - # Helper to return whether a passed value is a UUID - # 7C3CFDDF-920A-4924-AED6-7CD4AF6E4512 - if not isinstance(value,str): return False # Wrong type - value = value.lower() - # Check that all chars are hex or the separator - if not all((x in "-0123456789abcdef" for x in value)): return False - len_list = (8,4,4,4,12) - chunks = value.split("-") - # Make sure we have the right number of chunks - and - # each chunk is the right length. - if not len(chunks)==len(len_list): return False - for i,chunk in enumerate(chunks): - if not len(chunk)==len_list[i]: return False - # Passed all the checks - return True - - def get_partition_scheme(self, disk, allow_logical = True, disk_dict = None): - # let's resolve the disk to its physical parents - comm = self.get_parent_disk if allow_logical else self.get_physical_parent_disks - p = comm(disk,disk_dict=disk_dict) - if p: - if isinstance(p,(list,tuple)): p = p[0] # Extract the first parent if need be - if p.get("apfs"): return "APFS_container_scheme" - elif p.get("core_storage"): return "Core_Storage_container_scheme" - content = self.get_content(p,disk_dict=disk_dict) - if content.lower().endswith("scheme"): - return content - - def get_readable_partition_scheme(self, disk, allow_logical = True, disk_dict = None): - s = self.get_partition_scheme(disk,disk_dict=disk_dict) - if not s: return - # We want to convert GUID_partition_scheme to GUID - # We also want to translate FDisk to MBR - joined = " ".join(["MBR" if x.lower() == "fdisk" else x.capitalize() if x!=x.upper() else x for x in s.replace("_"," ").split() if x]) - return joined - - def get_content(self, disk, disk_dict = None): - return self._get_value(disk,"DAMediaContent",disk_dict=disk_dict) - - def get_volume_name(self, disk, disk_dict = None): - return self._get_value(disk,"DAVolumeName",disk_dict=disk_dict) - - def get_volume_uuid(self, disk, disk_dict = None): - return self._get_value(disk,"DAVolumeUUID",disk_dict=disk_dict) - - def get_disk_uuid(self, disk, disk_dict = None): - return self._get_value(disk,"DAMediaUUID",disk_dict=disk_dict) - - def get_mount_point(self, disk, disk_dict = None): - return self._get_value(disk,"DAVolumePath",disk_dict=disk_dict) - - def open_mount_point(self, disk, new_window = False, disk_dict = None): - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - mount = self.get_mount_point(disk) - if not mount: return - return self.r.run({"args":["open", mount]})[2] == 0 - - def compare_version(self, v1, v2): - # Splits the version numbers by periods and compare each value - # Allows 0.0.10 > 0.0.9 where normal string comparison would return false - # Also strips out any non-numeric values from each segment to avoid conflicts - # - # Returns True if v1 > v2, None if v1 == v2, and False if v1 < v2 - if not all((isinstance(x,str) for x in (v1,v2))): - # Wrong types - return False - v1_seg = v1.split(".") - v2_seg = v2.split(".") - # Pad with 0s to ensure common length - v1_seg += ["0"]*(len(v2_seg)-len(v1_seg)) - v2_seg += ["0"]*(len(v1_seg)-len(v2_seg)) - # Compare each segment - stripping non-numbers as needed - for i in range(len(v1_seg)): - a,b = v1_seg[i],v2_seg[i] - try: a = int("".join([x for x in a if x.isdigit()])) - except: a = 0 - try: b = int("".join([x for x in b if x.isdigit()])) - except: b = 0 - if a > b: return True - if a < b: return False - # If we're here, both versions are the same - return None - - def needs_sudo(self, disk = None, disk_dict = None): - # Default to EFI if we didn't pass a disk - if not disk: return self.compare_version(self.full_os_version,self.sudo_mount_version) in (True,None) - return self.compare_version(self.full_os_version,self.sudo_mount_version) in (True,None) and self.get_content(disk,disk_dict=disk_dict).upper() in self.efi_guids - - def mount_partition(self, disk, disk_dict = None): - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - sudo = self.needs_sudo(disk,disk_dict=disk_dict) - out = self.r.run({"args":["diskutil","mount",disk],"sudo":sudo}) - self.update() - return out - - def unmount_partition(self, disk, disk_dict = None): - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - out = self.r.run({"args":["diskutil","unmount",disk]}) - self.update() - return out - - def is_mounted(self, disk, disk_dict = None): - disk = self.get_identifier(disk,disk_dict=disk_dict) - if not disk: return - m = self.get_mount_point(disk,disk_dict=disk_dict) - return (m != None and len(m)) - - def get_volumes(self, disk_dict = None): - # Returns a list object with all volumes from disks - return sorted((disk_dict or self.disks).get("VolumesFromDisks",[])) - -if __name__ == '__main__': - d = Disk() - # Gather the args - errors = [] - args = [] - for x in sys.argv[1:]: - if x == "/": - args.append(x) - continue - if x.endswith("/"): - x = x[:-1] - if not x.lower().startswith("/volumes/") or len(x.split("/")) > 3: - errors.append("'{}' is not a volume.".format(x)) - continue - if not os.path.exists(x): - # Doesn't exist, skip it - errors.append("'{}' does not exist.".format(x)) - continue - args.append(x) - mount_list = [] - needs_sudo = d.needs_sudo() - for x in args: - name = d.get_volume_name(x) - if not name: name = "Untitled" - name = name.replace('"','\\"') # Escape double quotes in names - efi = d.get_efi(x) - if efi: mount_list.append((efi,name,d.is_mounted(efi),"diskutil mount {}".format(efi))) - else: errors.append("'{}' has no ESP.".format(name)) - if mount_list: - # We have something to mount - efis = [x[-1] for x in mount_list if not x[2]] # Only mount those that aren't mounted - names = [x[1] for x in mount_list if not x[2]] - if efis: # We have something to mount here - command = "do shell script \"{}\" with prompt \"MountEFI would like to mount the ESP{} on {}\"{}".format( - "; ".join(efis), - "s" if len(names) > 1 else "", - ", ".join(names), - " with administrator privileges" if needs_sudo else "") - o,e,r = d.r.run({"args":["osascript","-e",command]}) - if r > 0 and len(e.strip()) and e.strip().lower().endswith("(-128)"): exit() # User canceled, bail - # Update the disks - d.update() - # Walk the mounts and find out which aren't mounted - for efi,name,mounted,comm in mount_list: - mounted_at = d.get_mount_point(efi) - if mounted_at: d.open_mount_point(mounted_at) - else: errors.append("ESP for '{}' failed to mount.".format(name)) - else: - errors.append("No disks with ESPs selected.") - if errors: - # Display our errors before we leave - d.r.run({"args":["osascript","-e","display dialog \"{}\" buttons {{\"OK\"}} default button \"OK\" with icon caution".format("\n".join(errors))]}) \ No newline at end of file diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump deleted file mode 100755 index b81958f..0000000 Binary files a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump and /dev/null differ diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py deleted file mode 100755 index e47ddd4..0000000 --- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py +++ /dev/null @@ -1,612 +0,0 @@ -### ### -# Imports # -### ### - -import datetime, os, plistlib, struct, sys, itertools -from io import BytesIO - -if sys.version_info < (3,0): - # Force use of StringIO instead of cStringIO as the latter - # has issues with Unicode strings - from StringIO import StringIO - -try: - basestring # Python 2 - unicode -except NameError: - basestring = str # Python 3 - unicode = str - -try: - FMT_XML = plistlib.FMT_XML - FMT_BINARY = plistlib.FMT_BINARY -except AttributeError: - FMT_XML = "FMT_XML" - FMT_BINARY = "FMT_BINARY" - -### ### -# Helper Methods # -### ### - -def wrap_data(value): - if not _check_py3(): return plistlib.Data(value) - return value - -def extract_data(value): - if not _check_py3() and isinstance(value,plistlib.Data): return value.data - return value - -def _check_py3(): - return sys.version_info >= (3, 0) - -def _is_binary(fp): - if isinstance(fp, basestring): - return fp.startswith(b"bplist00") - header = fp.read(32) - fp.seek(0) - return header[:8] == b'bplist00' - -### ### -# Deprecated Functions - Remapped # -### ### - -def readPlist(pathOrFile): - if not isinstance(pathOrFile, basestring): - return load(pathOrFile) - with open(pathOrFile, "rb") as f: - return load(f) - -def writePlist(value, pathOrFile): - if not isinstance(pathOrFile, basestring): - return dump(value, pathOrFile, fmt=FMT_XML, sort_keys=True, skipkeys=False) - with open(pathOrFile, "wb") as f: - return dump(value, f, fmt=FMT_XML, sort_keys=True, skipkeys=False) - -### ### -# Remapped Functions # -### ### - -def load(fp, fmt=None, use_builtin_types=None, dict_type=dict): - if _check_py3(): - use_builtin_types = True if use_builtin_types == None else use_builtin_types - # We need to monkey patch this to allow for hex integers - code taken/modified from - # https://github.com/python/cpython/blob/3.8/Lib/plistlib.py - if fmt is None: - header = fp.read(32) - fp.seek(0) - for info in plistlib._FORMATS.values(): - if info['detect'](header): - P = info['parser'] - break - else: - raise plistlib.InvalidFileException() - else: - P = plistlib._FORMATS[fmt]['parser'] - try: - p = P(use_builtin_types=use_builtin_types, dict_type=dict_type) - except: - # Python 3.9 removed use_builtin_types - p = P(dict_type=dict_type) - if isinstance(p,plistlib._PlistParser): - # Monkey patch! - def end_integer(): - d = p.get_data() - value = int(d,16) if d.lower().startswith("0x") else int(d) - if -1 << 63 <= value < 1 << 63: - p.add_object(value) - else: - raise OverflowError("Integer overflow at line {}".format(p.parser.CurrentLineNumber)) - def end_data(): - try: - p.add_object(plistlib._decode_base64(p.get_data())) - except Exception as e: - raise Exception("Data error at line {}: {}".format(p.parser.CurrentLineNumber,e)) - p.end_integer = end_integer - p.end_data = end_data - return p.parse(fp) - elif not _is_binary(fp): - # Is not binary - assume a string - and try to load - # We avoid using readPlistFromString() as that uses - # cStringIO and fails when Unicode strings are detected - # Don't subclass - keep the parser local - from xml.parsers.expat import ParserCreate - # Create a new PlistParser object - then we need to set up - # the values and parse. - p = plistlib.PlistParser() - parser = ParserCreate() - parser.StartElementHandler = p.handleBeginElement - parser.EndElementHandler = p.handleEndElement - parser.CharacterDataHandler = p.handleData - # We also need to monkey patch this to allow for other dict_types, hex int support - # proper line output for data errors, and for unicode string decoding - def begin_dict(attrs): - d = dict_type() - p.addObject(d) - p.stack.append(d) - def end_integer(): - d = p.getData() - value = int(d,16) if d.lower().startswith("0x") else int(d) - if -1 << 63 <= value < 1 << 63: - p.addObject(value) - else: - raise OverflowError("Integer overflow at line {}".format(parser.CurrentLineNumber)) - def end_data(): - try: - p.addObject(plistlib.Data.fromBase64(p.getData())) - except Exception as e: - raise Exception("Data error at line {}: {}".format(parser.CurrentLineNumber,e)) - def end_string(): - d = p.getData() - if isinstance(d,unicode): - d = d.encode("utf-8") - p.addObject(d) - p.begin_dict = begin_dict - p.end_integer = end_integer - p.end_data = end_data - p.end_string = end_string - if isinstance(fp, unicode): - # Encode unicode -> string; use utf-8 for safety - fp = fp.encode("utf-8") - if isinstance(fp, basestring): - # It's a string - let's wrap it up - fp = StringIO(fp) - # Parse it - parser.ParseFile(fp) - return p.root - else: - use_builtin_types = False if use_builtin_types == None else use_builtin_types - try: - p = _BinaryPlistParser(use_builtin_types=use_builtin_types, dict_type=dict_type) - except: - # Python 3.9 removed use_builtin_types - p = _BinaryPlistParser(dict_type=dict_type) - return p.parse(fp) - -def loads(value, fmt=None, use_builtin_types=None, dict_type=dict): - if _check_py3() and isinstance(value, basestring): - # If it's a string - encode it - value = value.encode() - try: - return load(BytesIO(value),fmt=fmt,use_builtin_types=use_builtin_types,dict_type=dict_type) - except: - # Python 3.9 removed use_builtin_types - return load(BytesIO(value),fmt=fmt,dict_type=dict_type) -def dump(value, fp, fmt=FMT_XML, sort_keys=True, skipkeys=False): - if _check_py3(): - plistlib.dump(value, fp, fmt=fmt, sort_keys=sort_keys, skipkeys=skipkeys) - else: - if fmt == FMT_XML: - # We need to monkey patch a bunch here too in order to avoid auto-sorting - # of keys - writer = plistlib.PlistWriter(fp) - def writeDict(d): - if d: - writer.beginElement("dict") - items = sorted(d.items()) if sort_keys else d.items() - for key, value in items: - if not isinstance(key, basestring): - if skipkeys: - continue - raise TypeError("keys must be strings") - writer.simpleElement("key", key) - writer.writeValue(value) - writer.endElement("dict") - else: - writer.simpleElement("dict") - writer.writeDict = writeDict - writer.writeln("") - writer.writeValue(value) - writer.writeln("") - elif fmt == FMT_BINARY: - # Assume binary at this point - writer = _BinaryPlistWriter(fp, sort_keys=sort_keys, skipkeys=skipkeys) - writer.write(value) - else: - # Not a proper format - raise ValueError("Unsupported format: {}".format(fmt)) - -def dumps(value, fmt=FMT_XML, skipkeys=False, sort_keys=True): - if _check_py3(): - return plistlib.dumps(value, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys).decode("utf-8") - else: - # We avoid using writePlistToString() as that uses - # cStringIO and fails when Unicode strings are detected - f = StringIO() - dump(value, f, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys) - return f.getvalue() - -### ### -# Binary Plist Stuff For Py2 # -### ### - -# From the python 3 plistlib.py source: https://github.com/python/cpython/blob/3.7/Lib/plistlib.py -# Tweaked to function on Python 2 - -class InvalidFileException (ValueError): - def __init__(self, message="Invalid file"): - ValueError.__init__(self, message) - -_BINARY_FORMAT = {1: 'B', 2: 'H', 4: 'L', 8: 'Q'} - -_undefined = object() - -class _BinaryPlistParser: - """ - Read or write a binary plist file, following the description of the binary - format. Raise InvalidFileException in case of error, otherwise return the - root object. - see also: http://opensource.apple.com/source/CF/CF-744.18/CFBinaryPList.c - """ - def __init__(self, use_builtin_types, dict_type): - self._use_builtin_types = use_builtin_types - self._dict_type = dict_type - - def parse(self, fp): - try: - # The basic file format: - # HEADER - # object... - # refid->offset... - # TRAILER - self._fp = fp - self._fp.seek(-32, os.SEEK_END) - trailer = self._fp.read(32) - if len(trailer) != 32: - raise InvalidFileException() - ( - offset_size, self._ref_size, num_objects, top_object, - offset_table_offset - ) = struct.unpack('>6xBBQQQ', trailer) - self._fp.seek(offset_table_offset) - self._object_offsets = self._read_ints(num_objects, offset_size) - self._objects = [_undefined] * num_objects - return self._read_object(top_object) - - except (OSError, IndexError, struct.error, OverflowError, - UnicodeDecodeError): - raise InvalidFileException() - - def _get_size(self, tokenL): - """ return the size of the next object.""" - if tokenL == 0xF: - m = ord(self._fp.read(1)[0]) & 0x3 - s = 1 << m - f = '>' + _BINARY_FORMAT[s] - return struct.unpack(f, self._fp.read(s))[0] - - return tokenL - - def _read_ints(self, n, size): - data = self._fp.read(size * n) - if size in _BINARY_FORMAT: - return struct.unpack('>' + _BINARY_FORMAT[size] * n, data) - else: - if not size or len(data) != size * n: - raise InvalidFileException() - return tuple(int.from_bytes(data[i: i + size], 'big') - for i in range(0, size * n, size)) - - def _read_refs(self, n): - return self._read_ints(n, self._ref_size) - - def _read_object(self, ref): - """ - read the object by reference. - May recursively read sub-objects (content of an array/dict/set) - """ - result = self._objects[ref] - if result is not _undefined: - return result - - offset = self._object_offsets[ref] - self._fp.seek(offset) - token = ord(self._fp.read(1)[0]) - tokenH, tokenL = token & 0xF0, token & 0x0F - - if token == 0: # \x00 or 0x00 - result = None - - elif token == 8: # \x08 or 0x08 - result = False - - elif token == 9: # \x09 or 0x09 - result = True - - # The referenced source code also mentions URL (0x0c, 0x0d) and - # UUID (0x0e), but neither can be generated using the Cocoa libraries. - - elif token == 15: # \x0f or 0x0f - result = b'' - - elif tokenH == 0x10: # int - result = 0 - for k in range((2 << tokenL) - 1): - result = (result << 8) + ord(self._fp.read(1)) - # result = int.from_bytes(self._fp.read(1 << tokenL), - # 'big', signed=tokenL >= 3) - - elif token == 0x22: # real - result = struct.unpack('>f', self._fp.read(4))[0] - - elif token == 0x23: # real - result = struct.unpack('>d', self._fp.read(8))[0] - - elif token == 0x33: # date - f = struct.unpack('>d', self._fp.read(8))[0] - # timestamp 0 of binary plists corresponds to 1/1/2001 - # (year of Mac OS X 10.0), instead of 1/1/1970. - result = (datetime.datetime(2001, 1, 1) + - datetime.timedelta(seconds=f)) - - elif tokenH == 0x40: # data - s = self._get_size(tokenL) - if self._use_builtin_types: - result = self._fp.read(s) - else: - result = plistlib.Data(self._fp.read(s)) - - elif tokenH == 0x50: # ascii string - s = self._get_size(tokenL) - result = self._fp.read(s).decode('ascii') - result = result - - elif tokenH == 0x60: # unicode string - s = self._get_size(tokenL) - result = self._fp.read(s * 2).decode('utf-16be') - - # tokenH == 0x80 is documented as 'UID' and appears to be used for - # keyed-archiving, not in plists. - - elif tokenH == 0xA0: # array - s = self._get_size(tokenL) - obj_refs = self._read_refs(s) - result = [] - self._objects[ref] = result - result.extend(self._read_object(x) for x in obj_refs) - - # tokenH == 0xB0 is documented as 'ordset', but is not actually - # implemented in the Apple reference code. - - # tokenH == 0xC0 is documented as 'set', but sets cannot be used in - # plists. - - elif tokenH == 0xD0: # dict - s = self._get_size(tokenL) - key_refs = self._read_refs(s) - obj_refs = self._read_refs(s) - result = self._dict_type() - self._objects[ref] = result - for k, o in zip(key_refs, obj_refs): - key = self._read_object(k) - if isinstance(key, plistlib.Data): - key = key.data - result[key] = self._read_object(o) - - else: - raise InvalidFileException() - - self._objects[ref] = result - return result - -def _count_to_size(count): - if count < 1 << 8: - return 1 - - elif count < 1 << 16: - return 2 - - elif count << 1 << 32: - return 4 - - else: - return 8 - -_scalars = (str, int, float, datetime.datetime, bytes) - -class _BinaryPlistWriter (object): - def __init__(self, fp, sort_keys, skipkeys): - self._fp = fp - self._sort_keys = sort_keys - self._skipkeys = skipkeys - - def write(self, value): - - # Flattened object list: - self._objlist = [] - - # Mappings from object->objectid - # First dict has (type(object), object) as the key, - # second dict is used when object is not hashable and - # has id(object) as the key. - self._objtable = {} - self._objidtable = {} - - # Create list of all objects in the plist - self._flatten(value) - - # Size of object references in serialized containers - # depends on the number of objects in the plist. - num_objects = len(self._objlist) - self._object_offsets = [0]*num_objects - self._ref_size = _count_to_size(num_objects) - - self._ref_format = _BINARY_FORMAT[self._ref_size] - - # Write file header - self._fp.write(b'bplist00') - - # Write object list - for obj in self._objlist: - self._write_object(obj) - - # Write refnum->object offset table - top_object = self._getrefnum(value) - offset_table_offset = self._fp.tell() - offset_size = _count_to_size(offset_table_offset) - offset_format = '>' + _BINARY_FORMAT[offset_size] * num_objects - self._fp.write(struct.pack(offset_format, *self._object_offsets)) - - # Write trailer - sort_version = 0 - trailer = ( - sort_version, offset_size, self._ref_size, num_objects, - top_object, offset_table_offset - ) - self._fp.write(struct.pack('>5xBBBQQQ', *trailer)) - - def _flatten(self, value): - # First check if the object is in the object table, not used for - # containers to ensure that two subcontainers with the same contents - # will be serialized as distinct values. - if isinstance(value, _scalars): - if (type(value), value) in self._objtable: - return - - elif isinstance(value, plistlib.Data): - if (type(value.data), value.data) in self._objtable: - return - - elif id(value) in self._objidtable: - return - - # Add to objectreference map - refnum = len(self._objlist) - self._objlist.append(value) - if isinstance(value, _scalars): - self._objtable[(type(value), value)] = refnum - elif isinstance(value, plistlib.Data): - self._objtable[(type(value.data), value.data)] = refnum - else: - self._objidtable[id(value)] = refnum - - # And finally recurse into containers - if isinstance(value, dict): - keys = [] - values = [] - items = value.items() - if self._sort_keys: - items = sorted(items) - - for k, v in items: - if not isinstance(k, basestring): - if self._skipkeys: - continue - raise TypeError("keys must be strings") - keys.append(k) - values.append(v) - - for o in itertools.chain(keys, values): - self._flatten(o) - - elif isinstance(value, (list, tuple)): - for o in value: - self._flatten(o) - - def _getrefnum(self, value): - if isinstance(value, _scalars): - return self._objtable[(type(value), value)] - elif isinstance(value, plistlib.Data): - return self._objtable[(type(value.data), value.data)] - else: - return self._objidtable[id(value)] - - def _write_size(self, token, size): - if size < 15: - self._fp.write(struct.pack('>B', token | size)) - - elif size < 1 << 8: - self._fp.write(struct.pack('>BBB', token | 0xF, 0x10, size)) - - elif size < 1 << 16: - self._fp.write(struct.pack('>BBH', token | 0xF, 0x11, size)) - - elif size < 1 << 32: - self._fp.write(struct.pack('>BBL', token | 0xF, 0x12, size)) - - else: - self._fp.write(struct.pack('>BBQ', token | 0xF, 0x13, size)) - - def _write_object(self, value): - ref = self._getrefnum(value) - self._object_offsets[ref] = self._fp.tell() - if value is None: - self._fp.write(b'\x00') - - elif value is False: - self._fp.write(b'\x08') - - elif value is True: - self._fp.write(b'\x09') - - elif isinstance(value, int): - if value < 0: - try: - self._fp.write(struct.pack('>Bq', 0x13, value)) - except struct.error: - raise OverflowError(value) # from None - elif value < 1 << 8: - self._fp.write(struct.pack('>BB', 0x10, value)) - elif value < 1 << 16: - self._fp.write(struct.pack('>BH', 0x11, value)) - elif value < 1 << 32: - self._fp.write(struct.pack('>BL', 0x12, value)) - elif value < 1 << 63: - self._fp.write(struct.pack('>BQ', 0x13, value)) - elif value < 1 << 64: - self._fp.write(b'\x14' + value.to_bytes(16, 'big', signed=True)) - else: - raise OverflowError(value) - - elif isinstance(value, float): - self._fp.write(struct.pack('>Bd', 0x23, value)) - - elif isinstance(value, datetime.datetime): - f = (value - datetime.datetime(2001, 1, 1)).total_seconds() - self._fp.write(struct.pack('>Bd', 0x33, f)) - - elif isinstance(value, plistlib.Data): - self._write_size(0x40, len(value.data)) - self._fp.write(value.data) - - elif isinstance(value, basestring): - try: - t = value.encode('ascii') - self._write_size(0x50, len(value)) - except UnicodeEncodeError: - t = value.encode('utf-16be') - self._write_size(0x60, len(t) // 2) - self._fp.write(t) - - elif isinstance(value, (bytes, bytearray)): - self._write_size(0x40, len(value)) - self._fp.write(value) - - elif isinstance(value, (list, tuple)): - refs = [self._getrefnum(o) for o in value] - s = len(refs) - self._write_size(0xA0, s) - self._fp.write(struct.pack('>' + self._ref_format * s, *refs)) - - elif isinstance(value, dict): - keyRefs, valRefs = [], [] - - if self._sort_keys: - rootItems = sorted(value.items()) - else: - rootItems = value.items() - - for k, v in rootItems: - if not isinstance(k, basestring): - if self._skipkeys: - continue - raise TypeError("keys must be strings") - keyRefs.append(self._getrefnum(k)) - valRefs.append(self._getrefnum(v)) - - s = len(keyRefs) - self._write_size(0xD0, s) - self._fp.write(struct.pack('>' + self._ref_format * s, *keyRefs)) - self._fp.write(struct.pack('>' + self._ref_format * s, *valRefs)) - - else: - raise TypeError(value) diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py deleted file mode 100755 index b586adc..0000000 --- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py +++ /dev/null @@ -1,151 +0,0 @@ -import sys, subprocess, time, threading, shlex -try: - from Queue import Queue, Empty -except: - from queue import Queue, Empty - -ON_POSIX = 'posix' in sys.builtin_module_names - -class Run: - - def __init__(self): - return - - def _read_output(self, pipe, q): - try: - for line in iter(lambda: pipe.read(1), b''): - q.put(line) - except ValueError: - pass - pipe.close() - - def _create_thread(self, output): - # Creates a new queue and thread object to watch based on the output pipe sent - q = Queue() - t = threading.Thread(target=self._read_output, args=(output, q)) - t.daemon = True - return (q,t) - - def _stream_output(self, comm, shell = False): - output = error = "" - p = None - try: - if shell and type(comm) is list: - comm = " ".join(shlex.quote(x) for x in comm) - if not shell and type(comm) is str: - comm = shlex.split(comm) - p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True, close_fds=ON_POSIX) - # Setup the stdout thread/queue - q,t = self._create_thread(p.stdout) - qe,te = self._create_thread(p.stderr) - # Start both threads - t.start() - te.start() - - while True: - c = z = "" - try: c = q.get_nowait() - except Empty: pass - else: - sys.stdout.write(c) - output += c - sys.stdout.flush() - try: z = qe.get_nowait() - except Empty: pass - else: - sys.stderr.write(z) - error += z - sys.stderr.flush() - if not c==z=="": continue # Keep going until empty - # No output - see if still running - p.poll() - if p.returncode != None: - # Subprocess ended - break - # No output, but subprocess still running - stall for 20ms - time.sleep(0.02) - - o, e = p.communicate() - return (output+o, error+e, p.returncode) - except: - if p: - try: o, e = p.communicate() - except: o = e = "" - return (output+o, error+e, p.returncode) - return ("", "Command not found!", 1) - - def _decode(self, value, encoding="utf-8", errors="ignore"): - # Helper method to only decode if bytes type - if sys.version_info >= (3,0) and isinstance(value, bytes): - return value.decode(encoding,errors) - return value - - def _run_command(self, comm, shell = False): - c = None - try: - if shell and type(comm) is list: - comm = " ".join(shlex.quote(x) for x in comm) - if not shell and type(comm) is str: - comm = shlex.split(comm) - p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - c = p.communicate() - except: - if c == None: - return ("", "Command not found!", 1) - return (self._decode(c[0]), self._decode(c[1]), p.returncode) - - def run(self, command_list, leave_on_fail = False): - # Command list should be an array of dicts - if type(command_list) is dict: - # We only have one command - command_list = [command_list] - output_list = [] - for comm in command_list: - args = comm.get("args", []) - shell = comm.get("shell", False) - stream = comm.get("stream", False) - sudo = comm.get("sudo", False) - stdout = comm.get("stdout", False) - stderr = comm.get("stderr", False) - mess = comm.get("message", None) - show = comm.get("show", False) - - if not mess == None: - print(mess) - - if not len(args): - # nothing to process - continue - if sudo: - # Check if we have sudo - out = self._run_command(["which", "sudo"]) - if "sudo" in out[0]: - # Can sudo - if type(args) is list: - args.insert(0, out[0].replace("\n", "")) # add to start of list - elif type(args) is str: - args = out[0].replace("\n", "") + " " + args # add to start of string - - if show: - print(" ".join(args)) - - if stream: - # Stream it! - out = self._stream_output(args, shell) - else: - # Just run and gather output - out = self._run_command(args, shell) - if stdout and len(out[0]): - print(out[0]) - if stderr and len(out[1]): - print(out[1]) - # Append output - output_list.append(out) - # Check for errors - if leave_on_fail and out[2] != 0: - # Got an error - leave - break - if len(output_list) == 1: - # We only ran one command - just return that output - return output_list[0] - return output_list diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow b/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow deleted file mode 100644 index 6a5b8a5..0000000 --- a/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow +++ /dev/null @@ -1,146 +0,0 @@ - - - - - AMApplicationBuild - 512 - AMApplicationVersion - 2.10 - AMDocumentVersion - 2 - actions - - - action - - AMAccepts - - Container - List - Optional - - Types - - com.apple.applescript.object - - - AMActionVersion - 1.0.2 - AMApplication - - Automator - - AMParameterProperties - - source - - - AMProvides - - Container - List - Types - - com.apple.applescript.object - - - ActionBundlePath - /System/Library/Automator/Run AppleScript.action - ActionName - Run AppleScript - ActionParameters - - source - on run {input, parameters} # Hacky nonsense to export paths that aren't normally available set export to "export PATH=/usr/local/bin:/usr/local/sbin/:$PATH; " # Try to get the system python versions - starting with py 3 set python to "" repeat with py in {"python3", "python"} try set pypath to do shell script export & "which " & py if pypath is "/usr/bin/python3" then # Check if we're running 10.15 or newer - and verify "xcode-select -p" # runs properly before allowing the stub if (do shell script "sw_vers -productVersion") ≥ "10.15" then do shell script "xcode-select -p" end if end if do shell script export & "/usr/bin/env " & py & " -V" set python to py exit repeat on error errorMsg # Didn't resolve - onto the next end try end repeat if python is "" then my print_error("Could not locate python3 or python via /usr/bin/env!", "Please download and install the latest from python.org") return end if # If we got here - we have a python version to run. # Organize the input paths set passed_paths to "" repeat with the_path in input set the_text to quoted form of POSIX path of (the_path as text) as string set passed_paths to passed_paths & " " & the_text end repeat # Let's make sure we have disk.py file set target to "disk.py" # Get the contents of the ~/Library/Services folder, and look for disk.py to run set services to POSIX path of (path to home folder) & "Library/Services/" set quick_action_list to do shell script "ls -1 " & quoted form of services set quick_actions to paragraphs of quick_action_list repeat with qa in quick_actions set test_path to services & qa & "/Contents/Scripts/" & target if my check_exists(test_path) is "0" then # We got a valid path - let's run it do shell script export & "/usr/bin/env " & python & " " & quoted form of test_path & passed_paths return end if end repeat # If we got here - then we didn't find the quick action my print_error("Required files were not found!", "Please reinstall the latest Mount EFI quick action from https://github.com/corpnewt/MountEFI") return end run on check_exists(path) # Quick one-liner to abuse bash and see if a file/folder exists return do shell script "if [[ -e " & quoted form of path & " ]]; then echo 0; else echo 1; fi" end check_exists on print_error(header, footer) beep display alert header & " " & footer end print_error - - BundleIdentifier - com.apple.Automator.RunScript - CFBundleVersion - 1.0.2 - CanShowSelectedItemsWhenRun - - CanShowWhenRun - - Category - - AMCategoryUtilities - - Class Name - RunScriptAction - InputUUID - 34AED1F9-B31F-4927-A2F3-43392E378CAC - Keywords - - Run - - OutputUUID - EAB751F1-47E9-4256-9F92-ED4CD9CF95F5 - UUID - FDE567E1-0DA9-43F5-B7DC-9D30FD0B8553 - UnlocalizedApplications - - Automator - - arguments - - 0 - - default value - on run {input, parameters} - - (* Your script goes here *) - - return input -end run - name - source - required - 0 - type - 0 - uuid - 0 - - - isViewVisible - 1 - location - 301.500000:558.000000 - nibPath - /System/Library/Automator/Run AppleScript.action/Contents/Resources/Base.lproj/main.nib - - isViewVisible - 1 - - - connectors - - workflowMetaData - - applicationBundleIDsByPath - - applicationPaths - - inputTypeIdentifier - com.apple.Automator.fileSystemObject.folder - outputTypeIdentifier - com.apple.Automator.nothing - presentationMode - 15 - processesInput - 0 - serviceInputTypeIdentifier - com.apple.Automator.fileSystemObject.folder - serviceOutputTypeIdentifier - com.apple.Automator.nothing - serviceProcessesInput - 0 - systemImageName - NSTouchBarTransferDownload - useAutomaticInputType - 0 - workflowTypeIdentifier - com.apple.Automator.servicesMenu - - - diff --git a/Utils/ocvalidate/README.md b/Utils/ocvalidate/README.md deleted file mode 100644 index 0aaf5c6..0000000 --- a/Utils/ocvalidate/README.md +++ /dev/null @@ -1,140 +0,0 @@ -ocvalidate -==================== - -Utility to validate whether a `config.plist` matches requirements and conventions imposed by OpenCore. - -## Usage -- Pass one single path to `config.plist` to verify it. -- Pass `--version` for current supported OpenCore version. - -## Technical background -### At a glance -- ocvalidate firstly calls `OcSerializeLib` which performs fundamental checks in terms of syntax and semantics. After that, the following will be checked. -- The error message `` complained by `OcSerializeLib` indicates unknown keys that can be deprecated in new versions of OpenCore. Such keys should be ***removed*** in order to avoid undefined behaviours. -- Under active development, newer versions of OpenCore hardly have backward compatibility at this moment. As a result, please first run `ocvalidate --version` to check which version of OpenCore is supported, and thus please only use the specific version. - -### Global Rules -- All entries must be set once only. Duplication is strictly prohibited. -- All strings (fields with plist `String` format) throughout the whole config only accept ASCII printable characters at most. Stricter rules may apply. For instance, some fields only accept specified values, as indicated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf). -- All the paths relative to OpenCore root must be less than or equal to 128 bytes (`OC_STORAGE_SAFE_PATH_MAX`) in total including '\0' terminator. -- Most binary patches must have `Find`, `Replace`, `Mask` (if used), and `ReplaceMask` (if used) identical size set. Also, `Find` requires `Mask` (or `Replace` requires `ReplaceMask`) to be active (set to non-zero) for corresponding bits. -- `MinKernel` and `MaxKernel` entries should follow conventions specified in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf). (TODO: Bring decent checks for this) -- `MinKernel` cannot be a value that is below macOS 10.4 (Darwin version 8). -- Entries taking file system path only accept `0-9, A-Z, a-z, '_', '-', '.', '/', and '\'`. -- Device Paths (e.g. `PciRoot(0x0)/Pci(0x1b,0x0)`) only accept strings in canonic string format. -- Paths of UEFI Drivers only accept `0-9, A-Z, a-z, '_', '-', '.', and '/'`. -- Entries requiring bitwise operations (e.g. `ConsoleAttributes`, `PickerAttributes`, or `ScanPolicy`) only allow known bits stated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf) to be set. -- Entries involving GUID (mainly in Section `NVRAM`) must have correct format set. - -### ACPI -#### Add -- Entry[N]->Path: Only `.aml` and `.bin` filename suffix are accepted. - -### Booter -#### MmioWhitelist -- Entry[N]->Enabled: When at least one entry is enabled, `DevirtualiseMmio` in `Booter->Quirks` should be enabled. -#### Patch -- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted. -- Entry[N]->Identifier: Only `Any`, `Apple`, or a specified bootloader with `.efi` sufffix, are accepted. -#### Quirks -- When `AllowRelocationBlock` is enabled, `ProvideCustomSlide` should be enabled altogether. -- When `EnableSafeModeSlide` is enabled, `ProvideCustomSlide` should be enabled altogether. -- If `ProvideMaxSlide` is set to a number greater than zero, `ProvideCustomSlide` should be enabled altogether. -- `ResizeAppleGpuBars` must be set to `0` or `-1`. -- When `DisableVariableWrite`, `EnableWriteUnprotector`, or `ProvideCustomSlide` is enabled, `OpenRuntime.efi` should be loaded in `UEFI->Drivers`. - -### DeviceProperties -- Requirements here all follow Global Rules. - -### Kernel -#### Add -- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted. -- Entry[N]->BundlePath: Filename should have `.kext` suffix. -- Entry[N]->PlistPath: Filename should have `.plist` suffix. -- Entry[N]: If `Lilu.kext` is used, `DisableLinkeditJettison` should be enabled in `Kernel->Quirks`. -- `BrcmFirmwareRepo.kext` must not be injected by OpenCore. -- For some known kexts, their `BundlePath`, `ExecutablePath`, and `PlistPath` must match against each other. Current list of rules can be found [here](https://github.com/acidanthera/OpenCorePkg/blob/master/Utilities/ocvalidate/KextInfo.c). -- Plugin kext must be placed after parent kext. For example, [plugins of Lilu](https://github.com/acidanthera/Lilu/blob/master/KnownPlugins.md) must be placed after `Lilu.kext`. -#### Delete -- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted. -- Entry[N]->Identifier: At least one dot (`.`) should exist, because any identifier looks like a domain sequence (`vendor.product`). -#### Quirks -- `CustomSMBIOSGuid` requires `PlatformInfo->UpdateSMBIOSMode` set to `Custom`. -- `SetApfsTrimTimeout` cannot be a value that is greater than `MAX_UINT32`, or less than `-1`. -#### Scheme -- KernelArch: Only `Auto`, `i386`, `i386-user32`, or `x86_64` are accepted. -- KernelCache: Only `Auto`, `Cacheless`, `Mkext`, or `Prelinked` are accepted. - -### Misc -#### BlessOverride -- Entries cannot be `\EFI\Microsoft\Boot\bootmgfw.efi` or `\System\Library\CoreServices\boot.efi` since OpenCore knows these paths. -#### Boot -- HibernateMode: Only `None`, `Auto`, `RTC`, or `NVRAM` are accepted. -- PickerMode: Only `Builtin`, `External`, or `Apple` are accepted. -- `PickerAudioAssist` requires `AudioSupport` in `UEFI->Audio` to be enabled. -- LauncherOption: Only `Disabled`, `Full`, `Short`, or `System` are accepted. -- `LauncherPath` cannot be empty string. -#### Security -- AuthRestart: If enabled, `VirtualSMC.kext` should be present in `Kernel->Add`. -- DmgLoading: Only `Disabled`, `Signed`, or `Any` are accepted. -- Vault: Only `Optional`, `Basic`, or `Secure` are accepted. -- SecureBootModel: Only `Default`, `Disabled`, `j137`, `j680`, `j132`, `j174`, `j140k`, `j780`, `j213`, `j140a`, `j152f`, `j160`, `j230k`, `j214k`, `j223`, `j215`, `j185`, `j185f`, or `x86legacy` are accepted. -#### Serial -- RegisterAccessWidth: Only `8` or `32` are accepted. -- BaudRate: Only `921600`, `460800`, `230400`, `115200`, `57600`, `38400`, `19200`, `9600`, `7200`, `4800`, `3600`, `2400`, `2000`, `1800`, `1200`, `600`, `300`, `150`, `134`, `110`, `75`, or `50` are accepted. -- PciDeviceInfo: The last byte must be `0xFF`. -- PciDeviceInfo: Excluding the last byte `0xFF`, the rest must be divisible by 4. -- PciDeviceInfo: Maximum allowed size is 41. - -### NVRAM -- Requirements here all follow Global Rules. In addition, the following keys and values are checked: -#### gAppleBootVariableGuid (`7C436110-AB2A-4BBB-A880-FE41995C9F82`) -- `nvda_drv` must have type `Plist Data` with the value of `0x30` or `0x31`. -- `boot-args` must be an ASCII string (thus `Plist String`) without trailing `\0`. -- `bootercfg` must be an ASCII string (thus `Plist String`) without trailing `\0`. -- `csr-active-config` must have type `Plist Data` and have length of 4 bytes. -- `StartupMute` must have type `Plist Data` and have length of 1 byte. -- `SystemAudioVolume` must have type `Plist Data` and have length of 1 byte. -#### gAppleVendorVariableGuid (`4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14`) -- `UIScale` must have type `Plist Data` with the value of `0x01` or `0x02`. -- `FirmwareFeatures` must have type `Plist Data` and have length of 4 bytes. -- `ExtendedFirmwareFeatures` must have type `Plist Data` and have length of 8 bytes. -- `FirmwareFeaturesMask` must have type `Plist Data` and have length of 4 bytes. -- `ExtendedFirmwareFeatures` must have type `Plist Data` and have length of 8 bytes. -- `DefaultBackgroundColor` must have type `Plist Data` and have length of 4 bytes. Also, its last byte must be `0x00`. - -### PlatformInfo -- UpdateSMBIOSMode: Only `TryOverwrite`, `Create`, `Overwrite`, or `Custom` are accepted. -#### Generic -- SystemProductName: Only real Mac models are accepted. -- SystemMemoryStatus: Only `Auto`, `Upgradable`, or `Soldered` are accepted. -- SystemUUID: Only empty string, `OEM` or valid UUID are accepted. -- ProcessorType: Only known first byte can be set. - -### UEFI -#### APFS -- When `EnableJumpstart` is enabled, `ScanPolicy` in `Misc->Security` should have `OC_SCAN_ALLOW_FS_APFS` (bit 8) set, together with `OC_SCAN_FILE_SYSTEM_LOCK` (bit 0) set. Or `ScanPolicy` should be `0` (failsafe value). -#### Audio -- When `AudioSupport` is enabled, `AudioDevice` must be either empty or a valid path. -- When `AudioSupport` is enabled, `AudioOutMask` must be non-zero. -#### Quirks -- When `RequestBootVarRouting` is enabled, `OpenRuntime.efi` should be loaded in `UEFI->Drivers`. -- `ResizeGpuBars` must be set to an integer value between `-1` and `19`. -#### Drivers -- When `OpenUsbKbDxe.efi` is in use, `KeySupport` in `UEFI->Input` should never be enabled altogether. -- When `Ps2KeyboardDxe.efi` is in use, `KeySupport` in `UEFI->Input` should always be enabled altogether. -- `OpenUsbKbDxe.efi` and `Ps2KeyboardDxe.efi` should never co-exist. -- When HFS+ filesystem driver or `AudioDxe.efi` is in use, `ConnectDrivers` should be enabled altogether. -- When `OpenCanopy.efi` is in use, `PickerMode` in `Misc->Boot` should be set to `External`. -- When `OpenVariableRuntimeDxe.efi` is in use, its `LoadEarly` option must be set to `TRUE`. -- `OpenRuntime.efi` must be placed after `OpenVariableRuntimeDxe.efi` when both are in use. -- `LoadEarly` for any other driver but `OpenVariableRuntimeDxe.efi` and `OpenRuntime.efi` must be set to `FALSE`. -#### Input -- KeySupportMode: Only `Auto`, `V1`, `V2`, or `AMI` are accepted. -- When `PointerSupport` is enabled, the value of `PointerSupportMode` should only be `ASUS`. -#### Output -- `ClearScreenOnModeSwitch`, `IgnoreTextInGraphics`, `ReplaceTabWithSpace`, and `SanitiseClearScreen` only apply to `System` TextRenderer -- `Resolution` should match `NUMBERxNUMBER` or `NUMBERxNUMBER@NUMBER` sequences (unless it is an `Empty string` or is set to `Max`). -- `UIScale` must be set to an integer value between `-1` and `2`. -#### ReservedMemory -- Type: Only `Reserved`, `LoaderCode`, `LoaderData`, `BootServiceCode`, `BootServiceData`, `RuntimeCode`, `RuntimeData`, `Available`, `Persistent`, `UnusableMemory`, `ACPIReclaimMemory`, `ACPIMemoryNVS`, `MemoryMappedIO`, `MemoryMappedIOPortSpace`, or `PalCode` are accepted. diff --git a/Utils/ocvalidate/ocvalidate b/Utils/ocvalidate/ocvalidate deleted file mode 100755 index ff0d53f..0000000 Binary files a/Utils/ocvalidate/ocvalidate and /dev/null differ diff --git a/Utils/ocvalidate/ocvalidate.exe b/Utils/ocvalidate/ocvalidate.exe deleted file mode 100755 index f6127c5..0000000 Binary files a/Utils/ocvalidate/ocvalidate.exe and /dev/null differ diff --git a/Utils/ocvalidate/ocvalidate.linux b/Utils/ocvalidate/ocvalidate.linux deleted file mode 100755 index 6fb767c..0000000 Binary files a/Utils/ocvalidate/ocvalidate.linux and /dev/null differ