Last active
June 2, 2025 17:31
-
-
Save zx0r/e0f8c7c8a178163a8c62cdd554101ec3 to your computer and use it in GitHub Desktop.
DSDT Analyser dor Hackintosh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license_text = """ | |
License for Free Use with No Commercial Use | |
Copyright (c) 2025 spakk | |
Permission is hereby granted to any person obtaining a copy of this software and associated documentation files | |
to use the software free of charge and without restriction, including the rights to use, copy, modify, and | |
distribute the software, but strictly for non-commercial purposes only. | |
Restrictions: | |
The software may not be used for commercial purposes, meaning not for direct or indirect financial gain. | |
Any use aimed at commercial exploitation is prohibited without the express written consent of the copyright holder. | |
Disclaimer: | |
The software is provided "as is," without any express or implied warranty, including but not limited to the | |
warranties of merchantability or fitness for a particular purpose. In no event shall the authors or copyright | |
holders be liable for any damages arising from the use or inability to use the software. | |
""" | |
# -*- coding: utf-8 -*- | |
import os | |
import re | |
import shutil | |
import subprocess | |
from pathlib import Path | |
import tkinter as tk | |
from tkinter import filedialog, messagebox, scrolledtext | |
import locale | |
import gettext | |
# Einfache Übersetzungen (du kannst beliebig viele Sprachen ergänzen) | |
translations = { | |
"en": { | |
"OC & Clover DSDT Analyzer & SSDT-Force Generator": "OC & Clover DSDT Analyzer & SSDT-Force Generator", | |
"DSDT.aml auswählen": "Select DSDT.aml", | |
"Decompile DSDT.aml (iasl)": "Decompile DSDT.aml (iasl)", | |
"Analyse (If & Device)": "Analyze (If & Device)", | |
"SSDT-Force erstellen": "Generate SSDT-Force", | |
"OpenCore Patch erstellen": "Generate OpenCore Patch", | |
"Alle Critical Devices prüfen": "Check All Critical Devices", | |
"Individuelle SSDTs erzeugen": "Generate Individual SSDTs", | |
"✔ Decompilation erfolgreich.": "✔ Decompilation successful.", | |
"✘ Fehler: iasl.exe nicht gefunden. Bitte im Skriptordner oder System-PATH ablegen.": "✘ Error: iasl.exe not found. Please place it in the script folder or add it to the system PATH.", | |
} | |
# Sprache des Systems ermitteln | |
lang = locale.getdefaultlocale()[0] | |
lang = lang.split("_")[0] if lang else "en" | |
if lang not in translations: | |
lang = "en" # Fallback | |
# Übersetzungsfunktion | |
def _(text): | |
return translations.get(lang, {}).get(text, text) | |
# --- Internationalisierung (i18n) vorbereiten --- | |
localedir = Path(__file__).parent / "locales" | |
lang, _ = locale.getdefaultlocale() | |
if lang: | |
lang = lang.split('_')[0] | |
else: | |
lang = "en" | |
try: | |
t = gettext.translation("messages", localedir=localedir, languages=[lang]) | |
t.install() | |
_ = t.gettext | |
except FileNotFoundError: | |
_ = gettext.gettext | |
# --- Konfiguration --- | |
iasl_exe = "iasl.exe" # iasl.exe muss im Systempfad oder Skriptordner liegen | |
download_dir = Path.home() / "Downloads" / "DSDT-Analysis-Tool_dsdt" | |
download_dir.mkdir(parents=True, exist_ok=True) | |
critical_devices = {"HDEF", "HDAS", "GFX0", "IGPU", "VGA", "SAT0", "GLAN", "SBUS", "XHC", "XDCI"} | |
# --- Hilfsfunktionen --- | |
def evaluate_condition(cond_str): | |
# Placeholder für komplexe Evaluation (zurzeit nur Markierung) | |
return _("✔ {cond} (nicht evaluiert)").format(cond=cond_str) | |
def analyze_conditionals(dsdt_dsl_path): | |
conditional_info = [] | |
devices_found = [] | |
seen_devices = set() | |
with open(dsdt_dsl_path, "r", encoding="utf-8") as f: | |
lines = f.readlines() | |
pattern_if = re.compile(r"^\s*If\s*\((.+)\)") | |
pattern_device = re.compile(r"^\s*Device\s+\((\w+)\)") | |
for i, line in enumerate(lines): | |
m_if = pattern_if.search(line) | |
if m_if: | |
condition = m_if.group(1).strip() | |
# Max 15 Zeilen nach Device durchsuchen | |
for j in range(i + 1, min(i + 16, len(lines))): | |
m_dev = pattern_device.search(lines[j]) | |
if m_dev: | |
dev = m_dev.group(1) | |
if dev not in seen_devices: | |
eval_result = evaluate_condition(condition) | |
conditional_info.append((i + 1, condition, eval_result, dev)) | |
devices_found.append(dev) | |
seen_devices.add(dev) | |
break | |
return conditional_info, devices_found | |
def generate_ssdt_force(devices, output_path): | |
lines = [ | |
'DefinitionBlock ("", "SSDT", 2, "HACK", "Force", 0x00000001)', | |
'{', | |
' External (_SB_, DeviceObj)', | |
] | |
for dev in devices: | |
lines.append(f" External (_SB.{dev}, DeviceObj)") | |
for dev in devices: | |
lines.append(f""" | |
Scope (_SB) | |
{{ | |
Device ({dev}) | |
{{ | |
Name (_HID, "{dev}0000") // Dummy HID to force | |
}} | |
}} | |
""") | |
lines.append("}") | |
with open(output_path, "w", encoding="utf-8") as f: | |
f.write("\n".join(lines)) | |
def generate_oc_patches(devices, output_path): | |
patch_lines = [ | |
"# OpenCore ACPI Patch Template", | |
"# Automatically generated\n" | |
] | |
for dev in devices: | |
patch_lines.append(f"Patch for device label {dev}: set_label X{dev}") | |
with open(output_path, "w", encoding="utf-8") as f: | |
f.write("\n".join(patch_lines)) | |
def generate_conditional_devices_txt(devices, output_path): | |
with open(output_path, "w", encoding="utf-8") as f: | |
f.write("# Found conditional devices\n") | |
for dev in sorted(set(devices)): | |
f.write(dev + "\n") | |
def warn_missing_critical_devices(found_devices): | |
missing = critical_devices - set(found_devices) | |
if missing: | |
return "\n⚠️ " + _("Critical devices missing:") + "\n" + "\n".join(f" - {d}" for d in sorted(missing)) | |
return "" | |
def run_iasl(dsdt_aml_path, log_func): | |
iasl_path = shutil.which("iasl.exe") or shutil.which("iasl") or (Path(__file__).parent / "iasl.exe") | |
if not iasl_path or not Path(iasl_path).is_file(): | |
log_func(_("✘ Fehler: iasl.exe nicht gefunden. Bitte im Skriptordner oder System-PATH ablegen.")) | |
return False | |
iasl_path = Path(iasl_path) | |
try: | |
# *** Korrektur hier: cwd muss Ordner sein, nicht Datei *** | |
subprocess.run( | |
[str(iasl_path), "-d", str(dsdt_aml_path)], | |
check=True, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
text=True, | |
cwd=dsdt_aml_path.parent # <-- Korrektur: Ordner der AML-Datei | |
) | |
log_func(_("✔ Decompilation erfolgreich.")) | |
return True | |
except subprocess.CalledProcessError as e: | |
log_func(_("✘ Fehler: iasl.exe Ausführung fehlgeschlagen.")) | |
log_func(e.stderr) | |
return False | |
except Exception as e: | |
log_func(_("✘ Unerwarteter Fehler bei Ausführung von iasl.exe: ") + str(e)) | |
return False | |
def check_all_devices_in_dsdt(dsdt_dsl_path, output_path): | |
with open(dsdt_dsl_path, "r", encoding="utf-8") as f: | |
content = f.read() | |
found_devices = set(re.findall(r"Device\s+\((\w+)\)", content)) | |
missing = critical_devices - found_devices | |
with open(output_path, "w", encoding="utf-8") as f: | |
f.write(_("Critical devices – Full analysis:\n\n")) | |
for dev in sorted(critical_devices): | |
status = _("✔ gefunden") if dev in found_devices else _("✘ fehlt") | |
f.write(f"{dev}: {status}\n") | |
return missing | |
def generate_individual_ssdts(devices, out_folder, log_func): | |
out_folder.mkdir(parents=True, exist_ok=True) | |
iasl_path = shutil.which("iasl.exe") or shutil.which("iasl") or (Path(__file__).parent / "iasl.exe") | |
if not iasl_path or not Path(iasl_path).is_file(): | |
log_func(_("✘ iasl.exe nicht gefunden zum Kompilieren individueller SSDTs.")) | |
return | |
iasl_path = Path(iasl_path) | |
for dev in devices: | |
ssdt = [ | |
f'DefinitionBlock ("", "SSDT", 2, "DRVN", "XXX_{dev}", 0x00000000)', | |
"{", | |
f" External (_SB_.{dev}, DeviceObj)", | |
" Scope (_SB)", | |
" {", | |
f" Device ({dev})", | |
" {", | |
' Name (_HID, "FAKE0000")', | |
" }", | |
" }", | |
"}" | |
] | |
ssdt_dsl_path = out_folder / f"SSDT-XXX-{dev}.dsl" | |
ssdt_aml_path = out_folder / f"SSDT-XXX-{dev}.aml" | |
with open(ssdt_dsl_path, "w", encoding="utf-8") as f: | |
f.write("\n".join(ssdt)) | |
try: | |
result = subprocess.run( | |
[str(iasl_path), str(ssdt_dsl_path)], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
text=True, | |
check=True, | |
cwd=out_folder | |
) | |
except subprocess.CalledProcessError as e: | |
log_func(f"✘ Fehler bei der Kompilierung von {ssdt_dsl_path.name}:") | |
log_func(e.stderr) | |
else: | |
if ssdt_aml_path.exists(): | |
log_func(f"✔ Erstellt: {ssdt_aml_path.name}") | |
else: | |
log_func(f"✘ Fehlgeschlagen: {ssdt_aml_path.name}") | |
# --- Tkinter GUI Klasse --- | |
class DSDTApp(tk.Tk): | |
def __init__(self): | |
super().__init__() | |
self.title(_("OC & Clover DSDT Analyzer & SSDT-Force Generator")) | |
self.geometry("800x700") | |
header_frame = tk.Frame(self) | |
header_frame.pack(fill=tk.X, pady=5) | |
self.label_toolname = tk.Label( | |
header_frame, | |
text="OC & Clover DSDT Analyzer & SSDT-Force Generator", | |
font=("TkDefaultFont", 18, "bold"), | |
fg="blue" | |
) | |
self.label_toolname.pack() | |
self.label_link = tk.Label( | |
header_frame, | |
text="#spakk# - https://www.insanelymac.com", | |
font=("TkDefaultFont", 12, "italic"), | |
fg="darkblue", | |
cursor="hand2" | |
) | |
self.label_link.pack() | |
self.label_link.bind("<Button-1>", lambda e: os.system("open https://github.com/packiyam/dsdt_analyzer")) | |
btn_frame = tk.Frame(self) | |
btn_frame.pack(pady=5, fill=tk.X) | |
self.btn_select_aml = tk.Button(btn_frame, text=_("DSDT.aml auswählen"), command=self.select_dsdt_aml) | |
self.btn_select_aml.pack(side=tk.LEFT, padx=5) | |
self.btn_decompile = tk.Button(btn_frame, text=_("Decompile DSDT.aml (iasl)"), command=self.decompile_dsdt) | |
self.btn_decompile.pack(side=tk.LEFT, padx=5) | |
self.btn_decompile["state"] = "disabled" | |
self.btn_analyze = tk.Button(btn_frame, text=_("Analyse (If & Device)"), command=self.analyze_dsdt) | |
self.btn_analyze.pack(side=tk.LEFT, padx=5) | |
self.btn_analyze["state"] = "disabled" | |
self.btn_generate_force_ssdt = tk.Button(btn_frame, text=_("SSDT-Force erstellen"), command=self.generate_ssdt_force) | |
self.btn_generate_force_ssdt.pack(side=tk.LEFT, padx=5) | |
self.btn_generate_force_ssdt["state"] = "disabled" | |
self.btn_generate_oc_patch = tk.Button(btn_frame, text=_("OpenCore Patch erstellen"), command=self.generate_oc_patch) | |
self.btn_generate_oc_patch.pack(side=tk.LEFT, padx=5) | |
self.btn_generate_oc_patch["state"] = "disabled" | |
self.btn_check_full_devices = tk.Button(btn_frame, text=_("Alle Critical Devices prüfen"), command=self.check_full_devices) | |
self.btn_check_full_devices.pack(side=tk.LEFT, padx=5) | |
self.btn_check_full_devices["state"] = "disabled" | |
self.btn_generate_individual_ssdt = tk.Button(btn_frame, text=_("Individuelle SSDTs erzeugen"), command=self.generate_individual_ssdts) | |
self.btn_generate_individual_ssdt.pack(side=tk.LEFT, padx=5) | |
self.btn_generate_individual_ssdt["state"] = "disabled" | |
self.text_output = scrolledtext.ScrolledText(self, width=100, height=30) | |
self.text_output.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) | |
self.dsdt_aml_path = None | |
self.dsdt_dsl_path = None | |
self.devices_found = [] | |
def log(self, msg): | |
self.text_output.insert(tk.END, msg + "\n") | |
self.text_output.see(tk.END) | |
def select_dsdt_aml(self): | |
file = filedialog.askopenfilename( | |
title=_("Wähle DSDT.aml"), | |
filetypes=[("AML Dateien", "*.aml"), ("Alle Dateien", "*.*")] | |
) | |
if not file: | |
return | |
self.dsdt_aml_path = Path(file) | |
self.log(_("DSDT.aml ausgewählt: ") + str(self.dsdt_aml_path)) | |
self.btn_decompile["state"] = "normal" | |
self.btn_analyze["state"] = "disabled" | |
self.btn_generate_force_ssdt["state"] = "disabled" | |
self.btn_generate_oc_patch["state"] = "disabled" | |
self.btn_check_full_devices["state"] = "disabled" | |
self.btn_generate_individual_ssdt["state"] = "disabled" | |
self.text_output.delete(1.0, tk.END) | |
def decompile_dsdt(self): | |
if not self.dsdt_aml_path or not self.dsdt_aml_path.exists(): | |
self.log(_("✘ Keine gültige DSDT.aml ausgewählt.")) | |
return | |
out_dsl = self.dsdt_aml_path.with_suffix(".dsl") | |
self.log(_("Starte Decompilierung...")) | |
success = run_iasl(self.dsdt_aml_path, self.log) | |
if success and out_dsl.exists(): | |
self.dsdt_dsl_path = out_dsl | |
self.log(_("Decompilierte Datei: ") + str(out_dsl)) | |
self.btn_analyze["state"] = "normal" | |
else: | |
self.log(_("✘ Decompilierung fehlgeschlagen.")) | |
self.btn_analyze["state"] = "disabled" | |
def analyze_dsdt(self): | |
if not self.dsdt_dsl_path or not self.dsdt_dsl_path.exists(): | |
self.log(_("✘ Keine dekompilierte DSDT (DSL) verfügbar.")) | |
return | |
self.log(_("Analysiere bedingte If-Device-Blöcke...")) | |
cond_info, devices = analyze_conditionals(self.dsdt_dsl_path) | |
self.devices_found = devices | |
self.text_output.delete(1.0, tk.END) | |
for (line_num, cond, eval_res, dev) in cond_info: | |
self.log(f"Zeile {line_num}: If ({cond}) -> {eval_res} (Device {dev})") | |
self.log(warn_missing_critical_devices(devices)) | |
self.btn_generate_force_ssdt["state"] = "normal" | |
self.btn_generate_oc_patch["state"] = "normal" | |
self.btn_check_full_devices["state"] = "normal" | |
self.btn_generate_individual_ssdt["state"] = "normal" | |
# Optional: Schreiben der Devices in Datei | |
dev_txt = self.dsdt_dsl_path.parent / "conditional_devices.txt" | |
generate_conditional_devices_txt(devices, dev_txt) | |
self.log(_("Gefundene Geräte in Datei gespeichert: ") + str(dev_txt)) | |
def generate_ssdt_force(self): | |
if not self.devices_found: | |
self.log(_("✘ Keine Geräte zum Erzeugen einer SSDT-Force.")) | |
return | |
out_file = self.dsdt_dsl_path.parent / "SSDT-Force.dsl" | |
generate_ssdt_force(self.devices_found, out_file) | |
self.log(_("SSDT-Force erstellt: ") + str(out_file)) | |
def generate_oc_patch(self): | |
if not self.devices_found: | |
self.log(_("✘ Keine Geräte zum Erzeugen eines OpenCore-Patches.")) | |
return | |
out_file = self.dsdt_dsl_path.parent / "OpenCore-Patch.txt" | |
generate_oc_patches(self.devices_found, out_file) | |
self.log(_("OpenCore-Patch erstellt: ") + str(out_file)) | |
def check_full_devices(self): | |
if not self.dsdt_dsl_path or not self.dsdt_dsl_path.exists(): | |
self.log(_("✘ Dekomplilierte DSDT (DSL) wird benötigt.")) | |
return | |
out_file = self.dsdt_dsl_path.parent / "full_device_check.txt" | |
missing = check_all_devices_in_dsdt(self.dsdt_dsl_path, out_file) | |
self.log(_("Geräte-Check abgeschlossen. Ergebnis in: ") + str(out_file)) | |
if missing: | |
self.log(_("⚠️ Fehlende Critical Devices: ") + ", ".join(missing)) | |
else: | |
self.log(_("Alle Critical Devices gefunden.")) | |
def generate_individual_ssdts(self): | |
if not self.devices_found: | |
self.log(_("✘ Keine Geräte zum Erzeugen individueller SSDTs.")) | |
return | |
out_folder = self.dsdt_dsl_path.parent / "Individual_SSDTs" | |
generate_individual_ssdts(self.devices_found, out_folder, self.log) | |
if __name__ == "__main__": | |
app = DSDTApp() | |
app.mainloop() |
Author
zx0r
commented
Jun 2, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment