detect.py: Strip incompatible hardware combos

ie. Non-Metal with Metal, Metal 3802 with Metal 31001
This commit is contained in:
Mykola Grymalyuk
2024-09-02 11:18:09 -06:00
parent 3585053633
commit 303a908248

View File

@@ -12,7 +12,7 @@ from enum import StrEnum
from pathlib import Path from pathlib import Path
from functools import cache from functools import cache
from .hardware.base import BaseHardware from .hardware.base import BaseHardware, HardwareVariantGraphicsSubclass
from .hardware.graphics import ( from .hardware.graphics import (
intel_iron_lake, intel_iron_lake,
@@ -331,23 +331,109 @@ class HardwarePatchsetDetection:
return value return value
def _strip_incompatible_hardware(self, present_hardware: list[BaseHardware]) -> list[BaseHardware]:
"""
Strip out incompatible hardware. Priority is given to Metal GPUs (specifically 31001 when applicable)
Notes:
- Non-Metal GPUs are stripped out if any Metal GPUs are present
- Metal 3802 GPUs are stripped out if Metal 31001 GPUs are present on macOS Sequoia or newer
"""
non_metal_gpu_present = False
metal_gpu_present = False
metal_3802_gpu_present = False
metal_31001_gpu_present = False
for hardware in present_hardware:
hardware: BaseHardware
sub_variant = hardware.hardware_variant_graphics_subclass()
if sub_variant == HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS:
metal_31001_gpu_present = True
elif sub_variant == HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS:
metal_3802_gpu_present = True
elif sub_variant == HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS:
non_metal_gpu_present = True
metal_gpu_present = metal_31001_gpu_present or metal_3802_gpu_present
if metal_gpu_present and non_metal_gpu_present:
logging.error("Cannot mix Metal and Non-Metal GPUs")
logging.error("Stripping out Non-Metal GPUs")
for hardware in list(present_hardware):
if hardware.hardware_variant_graphics_subclass() == HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS:
print(f" Stripping out {hardware.name()}")
present_hardware.remove(hardware)
if metal_3802_gpu_present and metal_31001_gpu_present and self._xnu_major >= os_data.sequoia.value:
logging.error("Cannot mix Metal 3802 and Metal 31001 GPUs on macOS Sequoia or newer")
logging.error("Stripping out Metal 3802 GPUs")
for hardware in list(present_hardware):
if hardware.hardware_variant_graphics_subclass() == HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS:
logging.error(f" Stripping out {hardware.name()}")
present_hardware.remove(hardware)
return present_hardware
def _handle_missing_network_connection(self, requirements: dict, device_properties: dict) -> tuple[dict, dict]:
"""
Sync network connection requirements
"""
if self._can_patch(requirements, ignore_keys=[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION]) is False:
return requirements, device_properties
logging.info("Network connection missing, checking whether network patches are applicable")
if self._already_has_networking_patches() is True:
logging.info("Network patches are already applied, requiring network connection")
return requirements, device_properties
if not any([key.startswith("Networking:") for key in device_properties.keys()]):
logging.info("Network patches are not applicable, requiring network connection")
return requirements, device_properties
logging.info("Network patches are applicable, removing other patches")
for key in list(device_properties.keys()):
if key.startswith("Networking:"):
continue
device_properties.pop(key, None)
requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] = False
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED] = False
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING] = False
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_REQUIRED] = False
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_MISSING] = False
return requirements, device_properties
def _handle_sip_breakdown(self, requirements: dict, required_sip_configs: list[str]) -> dict:
"""
Handle SIP breakdown
"""
current_sip_status = hex(py_sip_xnu.SipXnu().get_sip_status().value)
expected_sip_status = hex(self._convert_required_sip_config_to_int(required_sip_configs))
sip_string = f"Validation: Booted SIP: {current_sip_status} vs expected: {expected_sip_status}"
index = list(requirements.keys()).index(HardwarePatchsetValidation.SIP_ENABLED)
return dict(list(requirements.items())[:index+1] + [(sip_string, True)] + list(requirements.items())[index+1:])
def _detect(self) -> None: def _detect(self) -> None:
""" """
Detect patches for a given system Detect patches for a given system
""" """
present_hardware = []
device_properties = {} device_properties = {}
patches = {} patches = {}
requires_metallib_support_pkg = False requires_metallib_support_pkg = False
missing_metallib_support_pkg = False missing_metallib_support_pkg = False
requires_kernel_debug_kit = False requires_kernel_debug_kit = False
missing_kernel_debug_kit = False missing_kernel_debug_kit = False
has_nvidia_web_drivers = False has_nvidia_web_drivers = False
has_3802_gpu = False has_metal_3802_gpu = False
highest_amfi_level = amfi_detect.AmfiConfigDetectLevel.NO_CHECK highest_amfi_level = amfi_detect.AmfiConfigDetectLevel.NO_CHECK
required_sip_configs = [] required_sip_configs = []
# First pass to find all present hardware
for hardware in self._hardware_variants: for hardware in self._hardware_variants:
item: BaseHardware = hardware( item: BaseHardware = hardware(
xnu_major = self._xnu_major, xnu_major = self._xnu_major,
@@ -362,13 +448,19 @@ class HardwarePatchsetDetection:
continue continue
if item.native_os() is True: # Skip if native OS if item.native_os() is True: # Skip if native OS
continue continue
present_hardware.append(item)
present_hardware = self._strip_incompatible_hardware(present_hardware)
# Second pass to gather all properties
for item in present_hardware:
item: BaseHardware
device_properties[item.name()] = True device_properties[item.name()] = True
if item.name() == "Graphics: Nvidia Web Drivers": if item.name() == "Graphics: Nvidia Web Drivers":
has_nvidia_web_drivers = True has_nvidia_web_drivers = True
if item.name() in ["Graphics: Nvidia Kepler", "Graphics: Intel Ivy Bridge", "Graphics: Intel Haswell"]: if item.hardware_variant_graphics_subclass() == HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS:
has_3802_gpu = True has_metal_3802_gpu = True
for config in item.required_system_integrity_protection_configurations(): for config in item.required_system_integrity_protection_configurations():
if config not in required_sip_configs: if config not in required_sip_configs:
@@ -383,13 +475,11 @@ class HardwarePatchsetDetection:
patches.update(item.patches()) patches.update(item.patches())
if requires_metallib_support_pkg is True: if requires_metallib_support_pkg is True:
missing_metallib_support_pkg = not self._is_cached_metallib_support_pkg_present() missing_metallib_support_pkg = not self._is_cached_metallib_support_pkg_present()
if requires_kernel_debug_kit is True: if requires_kernel_debug_kit is True:
missing_kernel_debug_kit = not self._is_cached_kernel_debug_kit_present() missing_kernel_debug_kit = not self._is_cached_kernel_debug_kit_present()
requirements = { requirements = {
HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED: requires_kernel_debug_kit, HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED: requires_kernel_debug_kit,
HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING: missing_kernel_debug_kit, HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING: missing_kernel_debug_kit,
@@ -406,38 +496,16 @@ class HardwarePatchsetDetection:
HardwarePatchsetValidation.FORCE_OPENGL_MISSING: self._validation_check_force_opengl_missing() if has_nvidia_web_drivers is True else False, HardwarePatchsetValidation.FORCE_OPENGL_MISSING: self._validation_check_force_opengl_missing() if has_nvidia_web_drivers is True else False,
HardwarePatchsetValidation.FORCE_COMPAT_MISSING: self._validation_check_force_compat_missing() if has_nvidia_web_drivers is True else False, HardwarePatchsetValidation.FORCE_COMPAT_MISSING: self._validation_check_force_compat_missing() if has_nvidia_web_drivers is True else False,
HardwarePatchsetValidation.NVDA_DRV_MISSING: self._validation_check_nvda_drv_missing() if has_nvidia_web_drivers is True else False, HardwarePatchsetValidation.NVDA_DRV_MISSING: self._validation_check_nvda_drv_missing() if has_nvidia_web_drivers is True else False,
HardwarePatchsetValidation.HELL_SPAWN_GPU_PRESENT: has_3802_gpu and not self._dortania_internal_check(), HardwarePatchsetValidation.HELL_SPAWN_GPU_PRESENT: has_metal_3802_gpu and self._xnu_major >= os_data.sequoia.value and self._dortania_internal_check() is False,
} }
_cant_patch = False _cant_patch = False
_cant_unpatch = requirements[HardwarePatchsetValidation.SIP_ENABLED] _cant_unpatch = requirements[HardwarePatchsetValidation.SIP_ENABLED]
if requirements[HardwarePatchsetValidation.SIP_ENABLED] is True: if requirements[HardwarePatchsetValidation.SIP_ENABLED] is True:
current_sip_status = hex(py_sip_xnu.SipXnu().get_sip_status().value) requirements = self._handle_sip_breakdown(requirements, required_sip_configs)
expected_sip_status = hex(self._convert_required_sip_config_to_int(required_sip_configs))
sip_string = f"Validation: Booted SIP: {current_sip_status} vs expected: {expected_sip_status}"
index = list(requirements.keys()).index(HardwarePatchsetValidation.SIP_ENABLED)
requirements = dict(list(requirements.items())[:index+1] + [(sip_string, True)] + list(requirements.items())[index+1:])
# If MISSING_NETWORK_CONNECTION is enabled, see whether 'Networking: Legacy Wireless' or 'Networking: Modern Wireless' is present
# If so, remove other patches and set PATCHING_NOT_POSSIBLE to True
if requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] is True: if requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] is True:
if self._can_patch(requirements, ignore_keys=[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION]) is True: requirements, device_properties = self._handle_missing_network_connection(requirements, device_properties)
logging.info("Network connection missing, checking whether network patches are applicable")
if self._already_has_networking_patches() is True:
logging.info("Network patches are already applied, requiring network connection")
else:
if "Networking: Legacy Wireless" in device_properties or "Networking: Modern Wireless" in device_properties:
logging.info("Network patches are applicable, removing other patches")
for key in list(device_properties.keys()):
if key.startswith("Networking:"):
continue
device_properties.pop(key, None)
requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] = False
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED] = False
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING] = False
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_REQUIRED] = False
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_MISSING] = False
_cant_patch = not self._can_patch(requirements) _cant_patch = not self._can_patch(requirements)