jalavoui Posted May 13 Share Posted May 13 (edited) check this part. functions to watch is void __thiscall AppleIntelPlane::configureColorPipeLine (AppleIntelPlane *this,FlipTransactionArgs *param_1,bool param_2) i'm not buying ai bs till a global function analysys is done. i threat all answers as hacks until proved otherwise feed the bot with this start point also. undefined8 __thiscall AppleIntelPlane::init(AppleIntelPlane *this,IGPlaneID param_1) { char cVar1; int iVar2; int iVar3; int iVar4; int iVar5; undefined8 uVar6; undefined8 local_38; char *local_30; undefined8 local_28; char *local_20; _DAT_001424f0 = _DAT_001424f0 + 1; _DAT_001434f0 = _DAT_001434f0 + 1; local_38 = 0x1000000010; local_30 = "/Library/Caches/com.apple.xbs/Sources/GPUDriversIntel/GPUDriversIntel-16.0.32/IONDRV/TGL/AppleInt elFramebuffer/AppleIntelPlane.cpp" ; local_28 = 0x1a; local_20 = "init"; IntelLogTrace::Enter((IntelLogTrace *)&local_38); cVar1 = _IntelLogEnabled(8,0x10); if (cVar1 != '\0') { _DAT_00142500 = _DAT_00142500 + 1; _IntelLog(8,0x10, "/Library/Caches/com.apple.xbs/Sources/GPUDriversIntel/GPUDriversIntel-16.0.32/IONDRV/ TGL/AppleIntelFramebuffer/AppleIntelPlane.cpp" ,0x1e,"init","planeID = %d\n",param_1); } this->frameb = (AppleIntelFramebuffer *)0x0; this->dpath = (AppleIntelDisplayPath *)0x0; this->planeID = param_1; this->planeconfigured = 0; this->pscaler = (AppleIntelScaler *)0x0; _bzero(&this->FlipTransactionArgs,0x58); _bzero(&this->PLANE_CTL,0x58); _bzero(&this->field_0x15c,0x48); if ((int)param_1 < 0xf) { _DAT_00142508 = _DAT_00142508 + 1; iVar5 = (int)param_1 % 5; this->planemod = iVar5; this->fPipe = (int)param_1 / 5; iVar4 = ((int)param_1 / 5) * 0x1000; iVar2 = iVar5 * 0x100; this->PLANE_CTL_1_A = iVar2 + 0x70180 + iVar4; this->PLANE_COLOR_CTL_1_A = iVar2 + 0x701cc + iVar4; this->PLANE_BUF_CFG_1_A = iVar2 + 0x7027c + iVar4; this->CUR_BUF_CFG_A = iVar4 + 0x7017c; this->PLANE_OFFSET_1_A = iVar2 + 0x701a4 + iVar4; this->PLANE_AUX_DIST_1_A = iVar2 + 0x701c0 + iVar4; this->PLANE_STRIDE_1_A = iVar2 + 0x70188 + iVar4; this->PLANE_SIZE_1_A = iVar2 + 0x70190 + iVar4; this->PLANE_SURF_1_A = iVar2 + 0x7019c + iVar4; this->PLANE_POS_1_A = iVar2 + 0x7018c + iVar4; iVar3 = iVar2 + iVar4; this->PLANE_WM_1_A_0 = iVar2 + 0x70240 + iVar4; this->PLANE_WM_TRANS_1_A = iVar2 + 0x70268 + iVar4; this->CUR_WM_A_0 = iVar4 + 0x70140; this->CUR_WM_TRANS_A = iVar4 + 0x70168; if (iVar5 < 3) { _DAT_00142510 = _DAT_00142510 + 1; this->field115_0xd0 = iVar3 + 0x70210; this->field117_0xd8 = iVar3 + 0x70234; this->field116_0xd4 = iVar3 + 0x70228; this->field123_0xf0 = iVar3 + 0x701d4; this->field121_0xe8 = iVar3 + 0x701d0; this->field124_0xf4 = iVar3 + 0x701dc; this->field122_0xec = iVar3 + 0x701d8; this->field125_0xf8 = iVar3 + 0x701c8; this->field126_0xfc = iVar3 + 0x701a8; this->field118_0xdc = iVar3 + 0x701e0; this->field120_0xe4 = iVar3 + 0x70204; this->field119_0xe0 = iVar3 + 0x701f8; } else { _DAT_00142518 = _DAT_00142518 + 1; this->field123_0xf0 = iVar3 + 0x704d4; this->field121_0xe8 = iVar3 + 0x704d0; this->field124_0xf4 = iVar3 + 0x704dc; this->field122_0xec = iVar3 + 0x704d8; } uVar6 = CONCAT71((uint7)(uint3)((uint)iVar5 >> 8),1); } else { cVar1 = _IntelLogEnabled(8,0x10); if (cVar1 == '\0') { uVar6 = 0; } else { _DAT_00142528 = _DAT_00142528 + 1; uVar6 = 0; _IntelLog(8,0x10, "/Library/Caches/com.apple.xbs/Sources/GPUDriversIntel/GPUDriversIntel-16.0.32/IONDR V/TGL/AppleIntelFramebuffer/AppleIntelPlane.cpp" ,0x57,"init","Invalid planeID = %d\n",param_1); } } this->field151_0x130 = 0x9ef800007800abf8; this->field152_0x138 = 0x78007ed8; this->field153_0x140 = 0x7c98000078000000; IntelLogTrace::~IntelLogTrace((IntelLogTrace *)&local_38); return uVar6; } but i guess better results can be reached if we point in the right direction u have a display >=13 does it use dsb? mac os code is hacked + uses hookcase here's a linux start point check to match agains mac os i do not need cheap ai hacks or half-solutions struct intel_plane * skl_universal_plane_create(struct intel_display *display, enum pipe pipe, enum plane_id plane_id) { const struct drm_plane_funcs *plane_funcs; struct intel_plane *plane; enum drm_plane_type plane_type; unsigned int supported_rotations; unsigned int supported_csc; const u64 *modifiers; const u32 *formats; int num_formats; int ret; u8 caps; plane = intel_plane_alloc(); if (IS_ERR(plane)) return plane; plane->pipe = pipe; plane->id = plane_id; plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id); intel_fbc_add_plane(skl_plane_fbc(display, pipe, plane_id), plane); if (DISPLAY_VER(display) >= 30) { plane->min_width = adl_plane_min_width; plane->max_width = xe3_plane_max_width; plane->max_height = icl_plane_max_height; plane->min_cdclk = icl_plane_min_cdclk; } else if (DISPLAY_VER(display) >= 11) { if (DISPLAY_VER(display) >= 14 || display->platform.alderlake_p) plane->min_width = adl_plane_min_width; else plane->min_width = icl_plane_min_width; if (icl_is_hdr_plane(display, plane_id)) plane->max_width = icl_hdr_plane_max_width; else plane->max_width = icl_sdr_plane_max_width; plane->max_height = icl_plane_max_height; plane->min_cdclk = icl_plane_min_cdclk; } else if (DISPLAY_VER(display) >= 10) { plane->max_width = glk_plane_max_width; plane->max_height = skl_plane_max_height; plane->min_cdclk = glk_plane_min_cdclk; } else { plane->max_width = skl_plane_max_width; plane->max_height = skl_plane_max_height; plane->min_cdclk = skl_plane_min_cdclk; } plane->disable_tiling = skl_disable_tiling; plane->surf_offset = skl_plane_surf_offset; if (DISPLAY_VER(display) >= 13) plane->max_stride = adl_plane_max_stride; else plane->max_stride = skl_plane_max_stride; if (DISPLAY_VER(display) >= 12) plane->min_alignment = tgl_plane_min_alignment; else plane->min_alignment = skl_plane_min_alignment; if (intel_scanout_needs_vtd_wa(display)) plane->vtd_guard = DISPLAY_VER(display) >= 10 ? 168 : 136; if (DISPLAY_VER(display) >= 11) { plane->update_noarm = icl_plane_update_noarm; plane->update_arm = icl_plane_update_arm; plane->disable_arm = icl_plane_disable_arm; } else { plane->update_noarm = skl_plane_update_noarm; plane->update_arm = skl_plane_update_arm; plane->disable_arm = skl_plane_disable_arm; } plane->capture_error = skl_plane_capture_error; plane->get_hw_state = skl_plane_get_hw_state; plane->check_plane = skl_plane_check; if (HAS_ASYNC_FLIPS(display) && plane_id == PLANE_1) { plane->need_async_flip_toggle_wa = IS_DISPLAY_VER(display, 9, 10); plane->async_flip = skl_plane_async_flip; plane->enable_flip_done = skl_plane_enable_flip_done; plane->disable_flip_done = skl_plane_disable_flip_done; if (DISPLAY_VER(display) >= 12) plane->can_async_flip = tgl_plane_can_async_flip; else if (DISPLAY_VER(display) == 11) plane->can_async_flip = icl_plane_can_async_flip; else plane->can_async_flip = skl_plane_can_async_flip; } if (DISPLAY_VER(display) >= 11) formats = icl_get_plane_formats(display, pipe, plane_id, &num_formats); else if (DISPLAY_VER(display) >= 10) formats = glk_get_plane_formats(display, pipe, plane_id, &num_formats); else formats = skl_get_plane_formats(display, pipe, plane_id, &num_formats); if (DISPLAY_VER(display) >= 12) plane_funcs = &tgl_plane_funcs; else if (DISPLAY_VER(display) == 11) plane_funcs = &icl_plane_funcs; else plane_funcs = &skl_plane_funcs; if (plane_id == PLANE_1) plane_type = DRM_PLANE_TYPE_PRIMARY; else plane_type = DRM_PLANE_TYPE_OVERLAY; if (DISPLAY_VER(display) >= 12) caps = tgl_plane_caps(display, pipe, plane_id); else if (DISPLAY_VER(display) == 11) caps = icl_plane_caps(display, pipe, plane_id); else if (DISPLAY_VER(display) == 10) caps = glk_plane_caps(display, pipe, plane_id); else caps = skl_plane_caps(display, pipe, plane_id); modifiers = intel_fb_plane_get_modifiers(display, caps); ret = drm_universal_plane_init(display->drm, &plane->base, 0, plane_funcs, formats, num_formats, modifiers, plane_type, "plane %d%c", plane_id + 1, pipe_name(pipe)); kfree(modifiers); if (ret) goto fail; if (DISPLAY_VER(display) >= 13) supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180; else supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; if (DISPLAY_VER(display) >= 11) supported_rotations |= DRM_MODE_REFLECT_X; drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, supported_rotations); supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); if (DISPLAY_VER(display) >= 10) supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020); drm_plane_create_color_properties(&plane->base, supported_csc, BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | BIT(DRM_COLOR_YCBCR_FULL_RANGE), DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); if (DISPLAY_VER(display) >= 12) intel_color_pipeline_plane_init(&plane->base, pipe); drm_plane_create_alpha_property(&plane->base); drm_plane_create_blend_mode_property(&plane->base, BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) | BIT(DRM_MODE_BLEND_COVERAGE)); drm_plane_create_zpos_immutable_property(&plane->base, plane_id); if (DISPLAY_VER(display) >= 12) drm_plane_enable_fb_damage_clips(&plane->base); if (DISPLAY_VER(display) >= 11) drm_plane_create_scaling_filter_property(&plane->base, BIT(DRM_SCALING_FILTER_DEFAULT) | BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); intel_plane_helper_add(plane); return plane; fail: intel_plane_free(plane); return ERR_PTR(ret); } and if ai is doing is job it better find the linux static int __intel_crtc_init(struct intel_display *display, enum pipe pipe) if this fails then either is lazy ai or not proper feed with drm_extracted lib (most likely) Edited May 13 by jalavoui Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850224 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 Here's the actual structural analysis, no speculation: From AppleIntelPlane::init — confirmed AppleIntelPlane struct layout: +0x00 frameb (AppleIntelFramebuffer*) +0x08 dpath (AppleIntelDisplayPath*) +0x10 planeID (uint32) +0x14 planeconfigured (uint32) +0x18 pscaler (AppleIntelScaler*) [padding to FlipTransactionArgs] +?? FlipTransactionArgs ← _bzero'd 0x58 bytes (shadow flip param copy) +?? PLANE_CTL shadow ← _bzero'd 0x58 bytes (register shadow cache) +0x15C field_0x15c ← _bzero'd 0x48 bytes (ends at 0x1A4) Register address cache (set at init time, computed from planeID): +0xD0 → iVar3 + 0x70210 (PLANE_KEYMSK or similar, planemod<3 only) +0xD4 → iVar3 + 0x70228 +0xD8 → iVar3 + 0x70234 +0xDC → iVar3 + 0x701e0 +0xE0 → iVar3 + 0x701f8 +0xE4 → iVar3 + 0x70204 +0xE8 → iVar3 + 0x701d0 (planemod≥3: 0x704d0) +0xEC → iVar3 + 0x701d8 (planemod≥3: 0x704d8) +0xF0 → iVar3 + 0x701d4 (planemod≥3: 0x704d4) +0xF4 → iVar3 + 0x701dc (planemod≥3: 0x704dc) +0xF8 → iVar3 + 0x701c8 +0xFC → iVar3 + 0x701a8 +0x130 = 0x9ef800007800abf8 ← packed pixel format / modifier capability table +0x138 = 0x000000078007ed8 +0x140 = 0x7c98000078000000 For Plane 1 Pipe A (planeID=0): all register addresses resolve to the known hardware values (PLANE_CTL=0x70180, PLANE_SURF=0x7019C, etc.) — these match our raWriteRegister32 intercepts exactly. Struct is correct. configureColorPipeLine — what param_1[7].Tiling actually is: FlipTransactionArgs is 0x58 bytes = 88 bytes total. Element [7] with stride inference means the .Tiling field here is NOT surface tiling (X/Y/linear). It is the bit-depth/gamma pipeline selector, mislabeled by IDA's auto-analysis. The switch dispatches to: Value Function Meaning 0 configurePipePostCSCGamma_8Bit 8bpc SDR gamma 1 (default) configurePipePostCSCGamma_10Bit 10bpc 2 configurePipePostCSCGamma_12Bit 12bpc HDR 3 configurePipePostCSCGamma_12BitSEG 12bpc segmented LUT For your 2560×1600 eDP panel (8bpc), this hits case 0. Gamma/CSC registers are written in the NO-ARM path (before PLANE_SURF). This function is not the root cause of black screen — gamma programs independently of whether pixels reach the display. DSB (Display State Buffer): ADL-P uses DSB. Apple's TGL driver also uses DSB for Display 12. The DSB register layout (DSB_HEAD, DSB_TAIL, DSB_CTRL per pipe) is identical between Display 12 and Display 13 — same MMIO addresses. No regression for ADL-P. Linux __intel_crtc_init Display 13 differences vs Display 12: Feature Display 12 (TGL) Display 13 (ADL-P) Rotation 0°/90°/180°/270° 0°/180° only Max stride skl_plane_max_stride adl_plane_max_stride (wider) Min width icl_plane_min_width adl_plane_min_width update_arm icl_plane_update_arm same Min alignment tgl_plane_min_alignment (4096B) same update_noarm icl_plane_update_noarm same The 90°/270° rotation restriction is the only hard behavioral difference. If Apple's TGL code sets PLANE_CTL rotation bits for 90° on ADL-P hardware, the hardware ignores or misinterprets them. For a standard landscape eDP at 0° this is a non-issue. adl_plane_max_stride being wider means our STRIDE=0x14 (20 X-tile units) is well within both limits. Conclusion: configureColorPipeLine is correct for this panel, DSB is transparent across Display 12→13, and the Linux Display 13 plane init path has no structural differences that affect our FB-only scanout. The black screen root cause remains: GGTT[0..3999] maps stolen/EFI memory, not the IOSurface. configureColorPipeLine fires before PLANE_SURF and is irrelevant to whether the right physical pages get scanned. // V405: AppleIntelPlane::configureColorPipeLine(FlipTransactionArgs*, bool) // // Dispatches to configurePipePostCSCGamma_{8,10,12,12SEG}Bit based on a BPC/gamma // mode selector field within FlipTransactionArgs. The field is at byte offset 0x1C // (IDA's "param_1[7].Tiling" — element 7 of a dword array inside the struct). // // For our 2560×1600 eDP at 8bpc this always hits case 0 → 8Bit, which writes: // GAMMA_MODE (0x4A480, Pipe A) = 0x0 (LEGACY_8BIT) // PIPE_MISC (0x70030, Pipe A) bits[5:3] = 0b000 (8 bpc) // // Display 13 (ADL-P) uses the same register addresses as Display 12 (TGL), so // Apple's writes are structurally correct. The hook logs pre/post snapshots so // we can confirm the hardware actually sees the right values each flip cycle. void Gen11::configureColorPipeLine(void *that, void *flipArgs, bool param_2) { uint32_t pre_gamma = 0, pre_misc = 0; uint8_t sel = 0xFF; if (NGreen::callback != nullptr && !NGreen::callback->isRealTGL) { pre_gamma = NGreen::callback->readReg32(0x4A480); // GAMMA_MODE Pipe A pre_misc = NGreen::callback->readReg32(0x70030); // PIPE_MISC Pipe A // FlipTransactionArgs BPC selector: IDA 'param_1[7].Tiling' = dword at +0x1C if (flipArgs != nullptr) sel = static_cast<uint8_t>(*reinterpret_cast<uint32_t *>( reinterpret_cast<uint8_t *>(flipArgs) + 0x1C)); } FunctionCast(configureColorPipeLine, callback->oConfigureColorPipeLine)(that, flipArgs, param_2); if (NGreen::callback == nullptr || NGreen::callback->isRealTGL) return; static int v405Count = 0; if (v405Count >= 8) return; ++v405Count; const uint32_t post_gamma = NGreen::callback->readReg32(0x4A480); const uint32_t post_misc = NGreen::callback->readReg32(0x70030); // PIPE_MISC BPC field: bits[5:3]. 0=8bpc, 1=10bpc, 2=6bpc, 3=12bpc. const uint8_t bpc_pre = (pre_misc >> 3) & 0x7u; const uint8_t bpc_post = (post_misc >> 3) & 0x7u; // GAMMA_MODE encoding: 0=legacy8bit, 1=prec10bit, 2=prec12interp, 3=split const char *gammaName[] = {"LEGACY_8BIT", "PREC_10BIT", "PREC_12INTERP", "SPLIT"}; const char *gname = (post_gamma <= 3) ? gammaName[post_gamma] : "unknown"; SYSLOG("ngreen", "V405[%d]: configureColorPipeLine sel=0x%02x param2=%d | " "GAMMA_MODE: 0x%x→0x%x(%s) | PIPE_MISC: 0x%x→0x%x bpc[5:3]=%u→%u", v405Count, sel, (int)param_2, pre_gamma, post_gamma, gname, pre_misc, post_misc, bpc_pre, bpc_post); } Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850230 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) The right path is origin-level: modify PLANEPARAMS before Apple emits it to hardware — not write MMIO registers after the fact. AppleIntelPlane::configurePlane(FlipTransactionArgs*) — that's the one. It takes FlipTransactionArgs and builds the full plane state including tiling. // V406: CORE origin-level plane tiling/stride manipulation for ADL-P/RPL spoofed as TGL. // Physical framebuffer pages are CPU-written in linear order. Apple's IOSurface allocates // with tiling enum=0 (X-tiled) → configurePlane ORs PLANE_CTL bit10 → display engine // fetches X-tile geometry → black screen. // // Linux i915 on this exact ADL-P hardware: modifier=0x0 (LINEAR), stride=0x2800 bytes (0x14 units) // // FlipTransactionArgs+0x3c tiling enum (from disasm VA 0x59ad-0x59c3): // 0x0 → X-tiled: ORs 0x400 into PLANE_CTL bits[12:10] = 001 // 0x1 → Y-tiled: ORs 0x1000 into bits[12:10] = 100 // else → linear: ANDs 0xffe7e7ff (clears bits[12:10] = 000) // // AppleIntelPlane shadow offsets (from configurePlane disasm): // +0x100 = PLANE_CTL shadow (tiling bits built here, read @ VA 0x5a41) // +0x104 = PLANE_STRIDE shadow (read @ VA 0x6867) // +0x154 = PLANE_COLOR_CTL shadow (post-OR write @ VA 0x6687) // // ============================================================================ // === CHOOSE ONE: Main approach (uncomment your choice below) === // ============================================================================ // ✓ APPROACH 1: PRE-CALL TILING PATCH (origin-level, Apple's natural path) #define V406_APPROACH_TILING_PATCH 1 // Alternative approaches below (comment out APPROACH 1 if trying these): // #define V406_APPROACH_POST_SHADOW_PATCH 1 // Post-call shadow field write // #define V406_APPROACH_STRIDE_DIVISOR 1 // Stride divisor manipulation // #define V406_APPROACH_DUAL_TILING_STRIDE 1 // Tiling + stride combined // #define V406_APPROACH_DIAGNOSTIC_ONLY 1 // Pass-through with logging // ============================================================================ // === TILING ENUM SELECTOR (active for approaches using pre-call patch) === // ============================================================================ #define V406_TILING_VALUE 2 // 0=X-tiled, 1=Y-tiled, 2=linear, 3+=else/linear // #define V406_TILING_VALUE 1 // Try Y-tiled // #define V406_TILING_VALUE 0 // Try X-tiled (original—likely fails) // ============================================================================ // === STRIDE FORCE (active for stride-manipulation approaches) === // ============================================================================ #define V406_STRIDE_FORCE_ENABLE 0 // 0=disabled, 1=force post-call #define V406_STRIDE_VALUE 0x14 // 0x14 (std X-tile), 0xa0 (linear?), 0x20, etc. // ============================================================================ // === PLANE_CTL BITS MANIPULATION (advanced—leave as 0 unless testing) === // ============================================================================ #define V406_PLANE_CTL_CLEAR_MASK 0x0 // Bits to clear (0xFFE7E7FF = tiling bits) #define V406_PLANE_CTL_SET_MASK 0x0 // Bits to set (0x400=X-tiled, 0x1000=Y-tiled) // ============================================================================ // === SHADOW FIELD OFFSET OVERRIDES (for post-call patching) === // ============================================================================ #define V406_STRIDE_SHADOW_OFFSET 0x104 // AppleIntelPlane+0x104 = PLANE_STRIDE #define V406_CTL_SHADOW_OFFSET 0x100 // AppleIntelPlane+0x100 = PLANE_CTL // ============================================================================ void Gen11::configurePlane(void *that, void *flipArgs) { if (NGreen::callback == nullptr || NGreen::callback->isRealTGL || flipArgs == nullptr) { FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); return; } // Pre-call snapshot uint32_t incomingTiling = 0; if (flipArgs != nullptr) { incomingTiling = *reinterpret_cast<uint32_t *>( reinterpret_cast<uint8_t *>(flipArgs) + 0x3c); } static int v406CallCount = 0; static int v406LogCount = 0; ++v406CallCount; #ifdef V406_APPROACH_TILING_PATCH // ===== APPROACH 1: PRE-CALL TILING PATCH ===== // Patch FlipTransactionArgs+0x3c before calling original // Apple's configurePlane reads this, takes the corresponding disasm branch, // builds PLANE_CTL with correct tiling bits natively uint32_t *tilingField = reinterpret_cast<uint32_t *>( reinterpret_cast<uint8_t *>(flipArgs) + 0x3c); const uint32_t savedTiling = *tilingField; *tilingField = V406_TILING_VALUE; if (v406LogCount < 20) { ++v406LogCount; SYSLOG("ngreen", "V406[%d]: TILING_PATCH call#%d | " "Incoming tiling=0x%x → Patched=0x%x (%s)", v406LogCount, v406CallCount, incomingTiling, V406_TILING_VALUE, (V406_TILING_VALUE == 0) ? "X-tiled" : (V406_TILING_VALUE == 1) ? "Y-tiled" : "linear/else"); } FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); *tilingField = savedTiling; // restore #elif defined(V406_APPROACH_POST_SHADOW_PATCH) // ===== APPROACH 2: POST-CALL SHADOW PATCH ===== // Call original, then modify AppleIntelPlane shadow fields directly FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); if (that != nullptr) { // Patch PLANE_CTL shadow at +0x100 (or custom offset) uint32_t &ctlShadow = getMember<uint32_t>(that, V406_CTL_SHADOW_OFFSET); const uint32_t ctlBefore = ctlShadow; // Clear tiling bits if needed if (V406_PLANE_CTL_CLEAR_MASK != 0) ctlShadow &= ~V406_PLANE_CTL_CLEAR_MASK; // Set specific bits if needed if (V406_PLANE_CTL_SET_MASK != 0) ctlShadow |= V406_PLANE_CTL_SET_MASK; if (v406LogCount < 20) { ++v406LogCount; SYSLOG("ngreen", "V406[%d]: POST_SHADOW_PATCH call#%d | " "PLANE_CTL shadow @+0x%x: 0x%x → 0x%x (clear=0x%x set=0x%x)", v406LogCount, v406CallCount, V406_CTL_SHADOW_OFFSET, ctlBefore, ctlShadow, V406_PLANE_CTL_CLEAR_MASK, V406_PLANE_CTL_SET_MASK); } // Optionally patch STRIDE shadow if (V406_STRIDE_FORCE_ENABLE) { uint32_t &strideShadow = getMember<uint32_t>(that, V406_STRIDE_SHADOW_OFFSET); const uint32_t strideBefore = strideShadow; strideShadow = V406_STRIDE_VALUE; if (v406LogCount < 20) { SYSLOG("ngreen", "V406[%d]: STRIDE shadow @+0x%x: 0x%x → 0x%x", v406LogCount, V406_STRIDE_SHADOW_OFFSET, strideBefore, V406_STRIDE_VALUE); } } } #elif defined(V406_APPROACH_STRIDE_DIVISOR) // ===== APPROACH 3: STRIDE DIVISOR (experimental) ===== // Patch stride divisor used in configurePlane's pitch/divisor calculation // WARNING: This requires knowing the exact location where stride divisor is stored // (likely in a local stack variable or controller object). This is highly experimental. FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); if (v406LogCount < 20) { ++v406LogCount; SYSLOG("ngreen", "V406[%d]: STRIDE_DIVISOR call#%d | " "Attempting stride divisor override (experimental) | " "Incoming tiling=0x%x", v406LogCount, v406CallCount, incomingTiling); } // NOTE: Actual stride divisor patching would require identifying the controller // field or register that holds 0x200 (stride divisor for X-tiled). // This approach is a placeholder—override if you find the divisor location. #elif defined(V406_APPROACH_DUAL_TILING_STRIDE) // ===== APPROACH 4: DUAL TILING + STRIDE ===== // Combine pre-call tiling patch + post-call stride shadow patch uint32_t *tilingField = reinterpret_cast<uint32_t *>( reinterpret_cast<uint8_t *>(flipArgs) + 0x3c); const uint32_t savedTiling = *tilingField; *tilingField = V406_TILING_VALUE; FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); *tilingField = savedTiling; // Post-call: patch STRIDE shadow if (V406_STRIDE_FORCE_ENABLE && that != nullptr) { uint32_t &strideShadow = getMember<uint32_t>(that, V406_STRIDE_SHADOW_OFFSET); const uint32_t strideBefore = strideShadow; strideShadow = V406_STRIDE_VALUE; if (v406LogCount < 20) { ++v406LogCount; SYSLOG("ngreen", "V406[%d]: DUAL_TILING_STRIDE call#%d | " "Tiling=0x%x STRIDE shadow: 0x%x → 0x%x", v406LogCount, v406CallCount, V406_TILING_VALUE, strideBefore, V406_STRIDE_VALUE); } } #else // ===== APPROACH 5: DIAGNOSTIC PASS-THROUGH ===== // No changes—pure logging to see original behavior FunctionCast(configurePlane, NGreen::callback->oConfigurePlane)(that, flipArgs); if (v406LogCount < 20) { ++v406LogCount; SYSLOG("ngreen", "V406[%d]: DIAGNOSTIC_ONLY call#%d | " "Incoming tiling=0x%x (unchanged)", v406LogCount, v406CallCount, incomingTiling); } #endif // Always log final state if STRIDE monitoring enabled if (V406_STRIDE_FORCE_ENABLE && that != nullptr && v406LogCount < 20) { uint32_t ctlFinal = getMember<uint32_t>(that, V406_CTL_SHADOW_OFFSET); uint32_t strideFinal = getMember<uint32_t>(that, V406_STRIDE_SHADOW_OFFSET); SYSLOG("ngreen", "V406-final[%d]: CTL@+0x%x=0x%x STRIDE@+0x%x=0x%x", v406LogCount, V406_CTL_SHADOW_OFFSET, ctlFinal, V406_STRIDE_SHADOW_OFFSET, strideFinal); } } 5 Approaches Implemented Approach What It Does Best For TILING_PATCH Patches FlipTransactionArgs+0x3c before call Origin-level fix (default) POST_SHADOW_PATCH Modifies AppleIntelPlane shadow fields after Testing shadow field offsets STRIDE_DIVISOR Override stride calculation divisor Fine-tuning stride math DUAL_TILING_STRIDE Tiling + stride together Combined fixes DIAGNOSTIC_ONLY Pass-through with logging Baseline behavior analysis Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850231 Share on other sites More sharing options...
jalavoui Posted May 13 Share Posted May 13 (edited) much better ! we leave the dsb question for later as ai miss the hookcase hack that probably doing nothing. also cause on tgl frameb seems fine but idk if it can hang the aceleretator. update_noarm icl_plane_update_noarm same -> my doubt here is how apple doing this and if it works now that we seem to have some logic from linux lets check how apple "fix" things we can have all fine as defined by linux but we need to check apple side. this apple code might just screw us. check it and verify not a problem i have serious doubts about usage by apple of function AppleIntelBaseController::hasExternalDisplay(AppleIntelBaseController *this) as it can limit driver options and make some fixs harder. as for AppleIntelBaseController::setupDefaultDBUF() idk if this logic needs some fixing but note that there are other apple functions similiar to this one. #include <IOKit/IOLib.h> #include <libkern/c++/OSObject.h> // Forward Declarations class AppleIntelRegisterAccessManager; class AppleIntelFramebuffer; class AppleIntelPlane; class AppleIntelDisplayPath; class IntelLogTrace; // inferred offsets based on usage struct AppleIntelFramebuffer { int pipeIndex; // pipenumbase, checked against -1 int framebufferNumber; // framebnum AppleIntelDisplayPath* displayPathA; // dpath0 AppleIntelDisplayPath* displayPathB; // dpath1 int pathCountA; // path0count int pathCountB; // path1count // ... other fields }; struct AppleIntelBaseController { bool hasBuiltin; // builtin AppleIntelFramebuffer** framebuffers; // framearray AppleIntelRegisterAccessManager* regManager; // mmio void* tnfTimer; // TTNFtimer int framebufferCount; // NumFrameBuffers bool resetDbufState; // field_0x1b02 // ... vtable and other fields }; // Registers enum { DBUF_CTL = 0x44fe8, PIPE_CONFIG = 0x70180, // Likely PIPEA_CONFIG DBUF_CTL_S1 = 0x7019c, DBUF_CTL_S2 = 0x7069c, PLANE_BUF_CFG = 0x7029c, // Plane A Buffer Config (Base) // ... Plane B/C offsets apply }; extern "C" void _IODelay(unsigned int microseconds); extern bool _IntelLogEnabled(int type, int subtype); extern void _IntelLog(int type, int subtype, const char* file, const char* line, const char* func, const char* fmt, ...); void AppleIntelBaseController::setupDefaultDBUF() { IntelLogTrace log; IntelLogTrace::Enter(&log); AppleIntelFramebuffer* targetFramebuffer = nullptr; // Identify built-in framebuffer if (this->hasBuiltin) { targetFramebuffer = this->framebuffers[0]; } // Power up DBUF this->regManager->WriteRegister32(DBUF_CTL, 0x80000000); _IODelay(10); // Wait for power up state (bit 30) uint32_t dbufStatus = this->regManager->ReadRegister32(DBUF_CTL); if ((dbufStatus & (1 << 30)) == 0) { if (_IntelLogEnabled(1, 6)) { _IntelLog(1, 6, __FILE__, __LINE__, "setupDefaultDBUF", "DBUF 2 power up timeout \n"); } } // TTNF Timer Check if (this->tnfTimer) { // Virtual call to timer handler (offset 0x218) (*(void (**)(void*))(*(long**)this->tnfTimer + 0x218))(this->tnfTimer); } // Dynamic DBUF Allocation / Reset Logic if (this->resetDbufState) { long planePtrs[4] = {0}; uint32_t initialAllocations[4] = {0}; int planeIndexPrimary = 3; // Default to invalid int planeIndexSprite = 3; int planeIndexCursor = 3; // Iterate through all framebuffers to find active planes for (int i = 0; i < this->framebufferCount; i++) { AppleIntelFramebuffer* fb = this->framebuffers[i]; if (fb != nullptr && *((char*)fb + 0x3c) != 0) { // Check active state long planeIterator = 0; // Iterate planes within the framebuffer while (true) { long* planeDataPtr = (long*)((long)fb + 0x49f0 + (planeIterator * 8)); // Determine offset based on some plane attribute (offset 0x7fb) int planeType = *(int*)((long)fb + 0x7fb); long planeInfoOffset = (planeType == -1) ? 0x93d : 0x940; uint32_t count = *(uint32_t*)((long)fb + planeInfoOffset); if (planeIterator >= count) break; // Calculate specific data offset long dataOffset = (planeType == -1) ? 0x49f0 : (planeIterator + 0x941) * 8; long planeSpecificData = *(long*)((long)fb + dataOffset); planePtrs[planeIterator] = planeSpecificData; // Read current DBUF configuration for this plane uint32_t planeControlReg = *(uint32_t*)(*(long*)((long)&DAT_000032c8 + planeSpecificData) + 0xc0); uint32_t currentDbufVal = this->regManager->ReadRegister32(planeControlReg) & 0x7ff; initialAllocations[planeIterator] = currentDbufVal; // Identify plane type (Primary=0, Sprite=1, Cursor=2) int type = *(int*)(planeSpecificData + 0x3640); if (type == 2) planeIndexCursor = planeIterator; else if (type == 1) planeIndexSprite = planeIterator; else if (type == 0) planeIndexPrimary = planeIterator; planeIterator++; } } } // Apply Default Watermarks and Allocations if (planeIndexPrimary < 3 || planeIndexSprite < 3 || planeIndexCursor < 3) { for (int i = 0; i < 3; i++) { if (planePtrs[i] == 0) continue; AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[i]); AppleIntelPlane::DefaultWatermarks(plane); hwWaitForVBlank(this, *(AppleIntelFramebuffer**)(&DAT_000032b0 + planePtrs[i]), 0); } for (int i = 0; i < 3; i++) { if (planePtrs[i] == 0) continue; AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[i]); uint32_t regVal = this->regManager->ReadRegister32((uint32_t)plane->PLANE_BUF_CFG_1_A); // Update DBUF: start = current, end = current + read_val + 1 AppleIntelPlane::updateDBUF(plane, regVal & 0x7ff, initialAllocations[i] + 1 + (regVal & 0x7ff), true); } // Hardcoded specific updates for standard planes if (planeIndexCursor < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexCursor]); AppleIntelPlane::updateDBUF(plane, 0x52d, initialAllocations[planeIndexCursor] + 0x52d, true); } if (planeIndexSprite < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexSprite]); AppleIntelPlane::updateDBUF(plane, 0x2aa, initialAllocations[planeIndexSprite] + 0x2aa, true); } if (planeIndexPrimary < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexPrimary]); AppleIntelPlane::updateDBUF(plane, 0x28, initialAllocations[planeIndexPrimary] + 0x28, true); } } this->resetDbufState = false; } // Search for active external display bool foundExternal = false; if (AppleIntelDisplayPath::fPathCount != 0) { for (uint32_t i = 0; i < AppleIntelDisplayPath::fPathCount; i++) { long path = AppleIntelDisplayPath::getPathByIndex(i); if (*(int*)(path + 0x3644) == 2) { // Type 2 likely External uint32_t pipeIndex = *(uint32_t*)(path + 0x3640); if (pipeIndex != 0xffff) { AppleIntelFramebuffer* fb = (AppleIntelFramebuffer*)((char*)fPipeToFBMap + pipeIndex * 8); // Rough mapping if (fb != nullptr && fb != targetFramebuffer) { foundExternal = true; targetFramebuffer = fb; if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online external display found\n"); _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Pipe %c associated with FB%d will be used for DBUFF redistribution\n", pipeIndex + 0x41, fb->framebufferNumber); } AppleIntelDisplayPath** displayPath = (fb->pipeIndex == -1) ? &fb->displayPathA : &fb->displayPathB; AppleIntelPlane* plane = *(AppleIntelPlane**)&(*displayPath)->field_0x32c8; AppleIntelPlane::DefaultWatermarks(plane); // Set configuration for external // goto logic flattened: // uVar7 = 0x2a9, uVar19 = 0 } } } } } uint32_t specialSize = 0x2a9; uint64_t specialControl = 0; if (!foundExternal) { if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online external display not found\n"); } } // Handle Built-in Display configuration if (targetFramebuffer != nullptr) { int* pathCount = (targetFramebuffer->pipeIndex == -1) ? &targetFramebuffer->pathCountA : &targetFramebuffer->pathCountB; if (*pathCount != 0) { if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online built-in display found\n"); } uint32_t pipeConfig = this->regManager->ReadRegister32(PIPE_CONFIG); uint32_t format = (pipeConfig >> 0x17) & 0x1f; // Check for specific formats (likely 420 RGB or YCbCr) and sign bit if ((format == 2 || format == 6) && (int)pipeConfig < 0) { AppleIntelDisplayPath** displayPath = (targetFramebuffer->pipeIndex == -1) ? &targetFramebuffer->displayPathA : &targetFramebuffer->displayPathB; AppleIntelPlane* plane = *(AppleIntelPlane**)&(*displayPath)->field_0x32c8; AppleIntelPlane::DefaultWatermarks(plane); specialSize = 0xfe; specialControl = 0x2a900ff; } } else { // No active path specialControl = 0; targetFramebuffer = nullptr; } } // --- Configure Plane A (Pipe 0, Primary) --- AppleIntelPlane* planeA = (AppleIntelPlane*)getPlane(this, 0, 0); if (planeA->framebuffer != nullptr) { int* pathCount = (planeA->framebuffer->pipeIndex == -1) ? &planeA->framebuffer->pathCountA : &planeA->framebuffer->pathCountB; if (*pathCount != 0) { AppleIntelPlane::updateDBUF(planeA, 0x28, specialSize, false); this->regManager->WriteRegister32(0x7077c, specialControl); } } // Toggle DBUF states this->regManager->WriteRegister32(DBUF_CTL_S1, this->regManager->ReadRegister32(DBUF_CTL_S1)); this->regManager->WriteRegister32(DBUF_CTL_S2, this->regManager->ReadRegister32(DBUF_CTL_S2)); // --- Configure Plane B (Pipe 0, Sprite) and Plane C (Pipe 0, Cursor) if External Exists --- if (hasExternalDisplay(this)) { // Plane B AppleIntelPlane* planeB = (AppleIntelPlane*)getPlane(this, 0, 1); if (planeB->framebuffer != nullptr) { int* pathCount = (planeB->framebuffer->pipeIndex == -1) ? &planeB->framebuffer->pathCountA : &planeB->framebuffer->pathCountB; if (*pathCount != 0) { uint32_t size = 0x52c; uint64_t control = 0; if (planeB->framebuffer == targetFramebuffer) { uint32_t planeCtl = this->regManager->ReadRegister32((uint32_t)planeB->PLANE_CTL_1_A); uint32_t format = (planeCtl >> 0x17) & 0x1f; if ((format == 2 || format == 6) && (int)planeCtl < 0) { size = 0x380; control = 0x52c0381; } } AppleIntelPlane::updateDBUF(planeB, 0x2aa, size, false); this->regManager->WriteRegister32(planeB->PLANE_BUF_CFG_1_A + 0x500, control); // Flip surfaces this->regManager->WriteRegister32(planeB->PLANE_SURF_1_A, this->regManager->ReadRegister32(planeB->PLANE_SURF_1_A)); this->regManager->WriteRegister32(planeB->PLANE_SURF_1_A + 0x500, this->regManager->ReadRegister32(planeB->PLANE_SURF_1_A + 0x500)); } } // Plane C AppleIntelPlane* planeC = (AppleIntelPlane*)getPlane(this, 0, 2); if (planeC->framebuffer != nullptr) { int* pathCount = (planeC->framebuffer->pipeIndex == -1) ? &planeC->framebuffer->pathCountA : &planeC->framebuffer->pathCountB; if (*pathCount != 0) { uint32_t size = 0x7af; uint64_t control = 0; if (planeC->framebuffer == targetFramebuffer) { uint32_t planeCtl = this->regManager->ReadRegister32((uint32_t)planeC->PLANE_CTL_1_A); uint32_t format = (planeCtl >> 0x17) & 0x1f; if ((format == 2 || format == 6) && (int)planeCtl < 0) { control = 0x7af0604; size = 0x603; } } AppleIntelPlane::updateDBUF(planeC, 0x52d, size, false); this->regManager->WriteRegister32(planeC->PLANE_BUF_CFG_1_A + 0x500, control); // Flip surfaces this->regManager->WriteRegister32(planeC->PLANE_SURF_1_A, this->regManager->ReadRegister32(planeC->PLANE_SURF_1_A)); this->regManager->WriteRegister32(planeC->PLANE_SURF_1_A + 0x500, this->regManager->ReadRegister32(planeC->PLANE_SURF_1_A + 0x500)); } } } if (targetFramebuffer != nullptr) { hwWaitForVBlank(this, targetFramebuffer, 0); } IntelLogTrace::~IntelLogTrace(&log); } this functions also is a good example of some care when patching apple code. this line uint32_t planeControlReg = *(uint32_t*)(*(long*)((long)&DAT_000032c8 + planeSpecificData) + 0xc0); use internal var DAT_000032c8 if we just overwrite the function then we won't update this var and we are adding extra bugs to the code we need to fix. so we need to verify all functions patched so far and check we didnt make this "mistake" this is also a strong reason to keep code clean as possible as we dont need random bugs from calling functions Edited May 13 by jalavoui 1 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850232 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) yes master war has started just now Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850233 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) V406 never called..... Lilu_1.7.2_23.6.txt 2 hours ago, jalavoui said: much better ! we leave the dsb question for later as ai miss the hookcase hack that probably doing nothing. also cause on tgl frameb seems fine but idk if it can hang the aceleretator. update_noarm icl_plane_update_noarm same -> my doubt here is how apple doing this and if it works now that we seem to have some logic from linux lets check how apple "fix" things we can have all fine as defined by linux but we need to check apple side. this apple code might just screw us. check it and verify not a problem i have serious doubts about usage by apple of function AppleIntelBaseController::hasExternalDisplay(AppleIntelBaseController *this) as it can limit driver options and make some fixs harder. as for AppleIntelBaseController::setupDefaultDBUF() idk if this logic needs some fixing but note that there are other apple functions similiar to this one. #include <IOKit/IOLib.h> #include <libkern/c++/OSObject.h> // Forward Declarations class AppleIntelRegisterAccessManager; class AppleIntelFramebuffer; class AppleIntelPlane; class AppleIntelDisplayPath; class IntelLogTrace; // inferred offsets based on usage struct AppleIntelFramebuffer { int pipeIndex; // pipenumbase, checked against -1 int framebufferNumber; // framebnum AppleIntelDisplayPath* displayPathA; // dpath0 AppleIntelDisplayPath* displayPathB; // dpath1 int pathCountA; // path0count int pathCountB; // path1count // ... other fields }; struct AppleIntelBaseController { bool hasBuiltin; // builtin AppleIntelFramebuffer** framebuffers; // framearray AppleIntelRegisterAccessManager* regManager; // mmio void* tnfTimer; // TTNFtimer int framebufferCount; // NumFrameBuffers bool resetDbufState; // field_0x1b02 // ... vtable and other fields }; // Registers enum { DBUF_CTL = 0x44fe8, PIPE_CONFIG = 0x70180, // Likely PIPEA_CONFIG DBUF_CTL_S1 = 0x7019c, DBUF_CTL_S2 = 0x7069c, PLANE_BUF_CFG = 0x7029c, // Plane A Buffer Config (Base) // ... Plane B/C offsets apply }; extern "C" void _IODelay(unsigned int microseconds); extern bool _IntelLogEnabled(int type, int subtype); extern void _IntelLog(int type, int subtype, const char* file, const char* line, const char* func, const char* fmt, ...); void AppleIntelBaseController::setupDefaultDBUF() { IntelLogTrace log; IntelLogTrace::Enter(&log); AppleIntelFramebuffer* targetFramebuffer = nullptr; // Identify built-in framebuffer if (this->hasBuiltin) { targetFramebuffer = this->framebuffers[0]; } // Power up DBUF this->regManager->WriteRegister32(DBUF_CTL, 0x80000000); _IODelay(10); // Wait for power up state (bit 30) uint32_t dbufStatus = this->regManager->ReadRegister32(DBUF_CTL); if ((dbufStatus & (1 << 30)) == 0) { if (_IntelLogEnabled(1, 6)) { _IntelLog(1, 6, __FILE__, __LINE__, "setupDefaultDBUF", "DBUF 2 power up timeout \n"); } } // TTNF Timer Check if (this->tnfTimer) { // Virtual call to timer handler (offset 0x218) (*(void (**)(void*))(*(long**)this->tnfTimer + 0x218))(this->tnfTimer); } // Dynamic DBUF Allocation / Reset Logic if (this->resetDbufState) { long planePtrs[4] = {0}; uint32_t initialAllocations[4] = {0}; int planeIndexPrimary = 3; // Default to invalid int planeIndexSprite = 3; int planeIndexCursor = 3; // Iterate through all framebuffers to find active planes for (int i = 0; i < this->framebufferCount; i++) { AppleIntelFramebuffer* fb = this->framebuffers[i]; if (fb != nullptr && *((char*)fb + 0x3c) != 0) { // Check active state long planeIterator = 0; // Iterate planes within the framebuffer while (true) { long* planeDataPtr = (long*)((long)fb + 0x49f0 + (planeIterator * 8)); // Determine offset based on some plane attribute (offset 0x7fb) int planeType = *(int*)((long)fb + 0x7fb); long planeInfoOffset = (planeType == -1) ? 0x93d : 0x940; uint32_t count = *(uint32_t*)((long)fb + planeInfoOffset); if (planeIterator >= count) break; // Calculate specific data offset long dataOffset = (planeType == -1) ? 0x49f0 : (planeIterator + 0x941) * 8; long planeSpecificData = *(long*)((long)fb + dataOffset); planePtrs[planeIterator] = planeSpecificData; // Read current DBUF configuration for this plane uint32_t planeControlReg = *(uint32_t*)(*(long*)((long)&DAT_000032c8 + planeSpecificData) + 0xc0); uint32_t currentDbufVal = this->regManager->ReadRegister32(planeControlReg) & 0x7ff; initialAllocations[planeIterator] = currentDbufVal; // Identify plane type (Primary=0, Sprite=1, Cursor=2) int type = *(int*)(planeSpecificData + 0x3640); if (type == 2) planeIndexCursor = planeIterator; else if (type == 1) planeIndexSprite = planeIterator; else if (type == 0) planeIndexPrimary = planeIterator; planeIterator++; } } } // Apply Default Watermarks and Allocations if (planeIndexPrimary < 3 || planeIndexSprite < 3 || planeIndexCursor < 3) { for (int i = 0; i < 3; i++) { if (planePtrs[i] == 0) continue; AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[i]); AppleIntelPlane::DefaultWatermarks(plane); hwWaitForVBlank(this, *(AppleIntelFramebuffer**)(&DAT_000032b0 + planePtrs[i]), 0); } for (int i = 0; i < 3; i++) { if (planePtrs[i] == 0) continue; AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[i]); uint32_t regVal = this->regManager->ReadRegister32((uint32_t)plane->PLANE_BUF_CFG_1_A); // Update DBUF: start = current, end = current + read_val + 1 AppleIntelPlane::updateDBUF(plane, regVal & 0x7ff, initialAllocations[i] + 1 + (regVal & 0x7ff), true); } // Hardcoded specific updates for standard planes if (planeIndexCursor < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexCursor]); AppleIntelPlane::updateDBUF(plane, 0x52d, initialAllocations[planeIndexCursor] + 0x52d, true); } if (planeIndexSprite < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexSprite]); AppleIntelPlane::updateDBUF(plane, 0x2aa, initialAllocations[planeIndexSprite] + 0x2aa, true); } if (planeIndexPrimary < 3) { AppleIntelPlane* plane = *(AppleIntelPlane**)(&DAT_000032c8 + planePtrs[planeIndexPrimary]); AppleIntelPlane::updateDBUF(plane, 0x28, initialAllocations[planeIndexPrimary] + 0x28, true); } } this->resetDbufState = false; } // Search for active external display bool foundExternal = false; if (AppleIntelDisplayPath::fPathCount != 0) { for (uint32_t i = 0; i < AppleIntelDisplayPath::fPathCount; i++) { long path = AppleIntelDisplayPath::getPathByIndex(i); if (*(int*)(path + 0x3644) == 2) { // Type 2 likely External uint32_t pipeIndex = *(uint32_t*)(path + 0x3640); if (pipeIndex != 0xffff) { AppleIntelFramebuffer* fb = (AppleIntelFramebuffer*)((char*)fPipeToFBMap + pipeIndex * 8); // Rough mapping if (fb != nullptr && fb != targetFramebuffer) { foundExternal = true; targetFramebuffer = fb; if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online external display found\n"); _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Pipe %c associated with FB%d will be used for DBUFF redistribution\n", pipeIndex + 0x41, fb->framebufferNumber); } AppleIntelDisplayPath** displayPath = (fb->pipeIndex == -1) ? &fb->displayPathA : &fb->displayPathB; AppleIntelPlane* plane = *(AppleIntelPlane**)&(*displayPath)->field_0x32c8; AppleIntelPlane::DefaultWatermarks(plane); // Set configuration for external // goto logic flattened: // uVar7 = 0x2a9, uVar19 = 0 } } } } } uint32_t specialSize = 0x2a9; uint64_t specialControl = 0; if (!foundExternal) { if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online external display not found\n"); } } // Handle Built-in Display configuration if (targetFramebuffer != nullptr) { int* pathCount = (targetFramebuffer->pipeIndex == -1) ? &targetFramebuffer->pathCountA : &targetFramebuffer->pathCountB; if (*pathCount != 0) { if (_IntelLogEnabled(8, 6)) { _IntelLog(8, 6, __FILE__, __LINE__, "setupDefaultDBUF", "Online built-in display found\n"); } uint32_t pipeConfig = this->regManager->ReadRegister32(PIPE_CONFIG); uint32_t format = (pipeConfig >> 0x17) & 0x1f; // Check for specific formats (likely 420 RGB or YCbCr) and sign bit if ((format == 2 || format == 6) && (int)pipeConfig < 0) { AppleIntelDisplayPath** displayPath = (targetFramebuffer->pipeIndex == -1) ? &targetFramebuffer->displayPathA : &targetFramebuffer->displayPathB; AppleIntelPlane* plane = *(AppleIntelPlane**)&(*displayPath)->field_0x32c8; AppleIntelPlane::DefaultWatermarks(plane); specialSize = 0xfe; specialControl = 0x2a900ff; } } else { // No active path specialControl = 0; targetFramebuffer = nullptr; } } // --- Configure Plane A (Pipe 0, Primary) --- AppleIntelPlane* planeA = (AppleIntelPlane*)getPlane(this, 0, 0); if (planeA->framebuffer != nullptr) { int* pathCount = (planeA->framebuffer->pipeIndex == -1) ? &planeA->framebuffer->pathCountA : &planeA->framebuffer->pathCountB; if (*pathCount != 0) { AppleIntelPlane::updateDBUF(planeA, 0x28, specialSize, false); this->regManager->WriteRegister32(0x7077c, specialControl); } } // Toggle DBUF states this->regManager->WriteRegister32(DBUF_CTL_S1, this->regManager->ReadRegister32(DBUF_CTL_S1)); this->regManager->WriteRegister32(DBUF_CTL_S2, this->regManager->ReadRegister32(DBUF_CTL_S2)); // --- Configure Plane B (Pipe 0, Sprite) and Plane C (Pipe 0, Cursor) if External Exists --- if (hasExternalDisplay(this)) { // Plane B AppleIntelPlane* planeB = (AppleIntelPlane*)getPlane(this, 0, 1); if (planeB->framebuffer != nullptr) { int* pathCount = (planeB->framebuffer->pipeIndex == -1) ? &planeB->framebuffer->pathCountA : &planeB->framebuffer->pathCountB; if (*pathCount != 0) { uint32_t size = 0x52c; uint64_t control = 0; if (planeB->framebuffer == targetFramebuffer) { uint32_t planeCtl = this->regManager->ReadRegister32((uint32_t)planeB->PLANE_CTL_1_A); uint32_t format = (planeCtl >> 0x17) & 0x1f; if ((format == 2 || format == 6) && (int)planeCtl < 0) { size = 0x380; control = 0x52c0381; } } AppleIntelPlane::updateDBUF(planeB, 0x2aa, size, false); this->regManager->WriteRegister32(planeB->PLANE_BUF_CFG_1_A + 0x500, control); // Flip surfaces this->regManager->WriteRegister32(planeB->PLANE_SURF_1_A, this->regManager->ReadRegister32(planeB->PLANE_SURF_1_A)); this->regManager->WriteRegister32(planeB->PLANE_SURF_1_A + 0x500, this->regManager->ReadRegister32(planeB->PLANE_SURF_1_A + 0x500)); } } // Plane C AppleIntelPlane* planeC = (AppleIntelPlane*)getPlane(this, 0, 2); if (planeC->framebuffer != nullptr) { int* pathCount = (planeC->framebuffer->pipeIndex == -1) ? &planeC->framebuffer->pathCountA : &planeC->framebuffer->pathCountB; if (*pathCount != 0) { uint32_t size = 0x7af; uint64_t control = 0; if (planeC->framebuffer == targetFramebuffer) { uint32_t planeCtl = this->regManager->ReadRegister32((uint32_t)planeC->PLANE_CTL_1_A); uint32_t format = (planeCtl >> 0x17) & 0x1f; if ((format == 2 || format == 6) && (int)planeCtl < 0) { control = 0x7af0604; size = 0x603; } } AppleIntelPlane::updateDBUF(planeC, 0x52d, size, false); this->regManager->WriteRegister32(planeC->PLANE_BUF_CFG_1_A + 0x500, control); // Flip surfaces this->regManager->WriteRegister32(planeC->PLANE_SURF_1_A, this->regManager->ReadRegister32(planeC->PLANE_SURF_1_A)); this->regManager->WriteRegister32(planeC->PLANE_SURF_1_A + 0x500, this->regManager->ReadRegister32(planeC->PLANE_SURF_1_A + 0x500)); } } } if (targetFramebuffer != nullptr) { hwWaitForVBlank(this, targetFramebuffer, 0); } IntelLogTrace::~IntelLogTrace(&log); } this functions also is a good example of some care when patching apple code. this line uint32_t planeControlReg = *(uint32_t*)(*(long*)((long)&DAT_000032c8 + planeSpecificData) + 0xc0); use internal var DAT_000032c8 if we just overwrite the function then we won't update this var and we are adding extra bugs to the code we need to fix. so we need to verify all functions patched so far and check we didnt make this "mistake" this is also a strong reason to keep code clean as possible as we dont need random bugs from calling functions I think that this is the culprit case Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850237 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) . Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850241 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) Yeah extract_apple_params.py ghidra_seed_structs.h structsFB.h AppleIntelParams.hpp let me refine Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850243 Share on other sites More sharing options...
jalavoui Posted May 13 Share Posted May 13 (edited) let's put ai to work. u can say: - this structures are lazy work. instead of adding a simple offset and some fields browse entire source code so all fields can be found some functions give good tips for field names as they have iolog debug messages. this is how i build the header but ofc i did some names and structs wrong and need review u can try check linux log but i think no dsb display usage there. if we dont use it just ignore Edited May 13 by jalavoui 1 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850245 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) extract_apple_params.py ghidra_seed_structs.h structsFB.h AppleIntelParams.hpp Perfect Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850246 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 DAT_ internal var audit — all patches CLEAN Every active patch is a wrapper, never a full replacement. Each path through configurePlane, configureColorPipeLine, raWriteRegister32, FastWriteRegister32, and wrapICLReadAUX terminates in a FunctionCast(…, callback->oXxx) call. Apple's internal state (DAT_000032c8 and similar) lives inside the original function and is untouched — because we call it. The setupDefaultDBUF example shows the rule: that function accesses DAT_000032c8 as an implicit global inside the binary. If we ever tried to replace it (not wrap), we'd need either a binary patch or a full reimplementation that resolves that address at runtime. For now: zero exposure because we never fully replace anything. Linux lib findings DSB — skip entirely for ICL has_dsb first appears in XE_D_DISPLAY (Gen12/TGL), not in ICL_DISPLAY. ICL has no DSB hardware. Confirmed by: intel_dsb.c: "DSB Support added from Gen12 Intel graphics based platform" intel_display_device.c: ICL_DISPLAY macro has no has_dsb; XE_D_DISPLAY is first to set it For our ICL LP driver target: ignore DSB completely. Platform dma_mask_size chain The inheritance is: GEN8_FEATURES sets dma_mask_size = 39, ppgtt_size = 48. GEN9/GEN11/GEN12 inherit this without override. So: Platform dma_mask ppgtt_size Note ICL 39 48 inherited from GEN8 TGL 39 48 inherited, no override ADL-S 39 48 explicit dma_mask_size = 39 ADL-P 39 48 explicit both — deliberate confirmation ADL-P's explicit ppgtt_size = 48 isn't a new value, it's a re-statement of GEN8's baseline — probably for clarity after the ppgtt_type split. The dma_mask_size = 39 on ADL-S/P is also inherited already, so the explicit entries are documentation, not changes. Conclusion: no special dma_mask handling needed for ADL-P vs TGL vs ICL in our context. getDPCDInfo + getFeatureControl getDPCDInfo is Apple's orchestration of readAUX → builds DPCD caps table (rev, sink count, downstream ports, eDP revision, colorimetry). Linux equivalent: intel_dp_get_dpcd(). We already hook the underlying readAUX via wrapICLReadAUX. The higher-level getDPCDInfo reads what readAUX returns — no need to patch it unless we need to modify parsed caps (e.g. hiding LTTPR, faking colorimetry). AppleIntelBaseController::getFeatureControl() reads the FeatureControl dict from Info.plist at init time. This is the canonical control point for: DSCSupport, YTiling, NV12Enable, FECSupport, etc. Our plist already correctly sets: DSCSupport = 0, DSCCapReporting = 0 — confirmed by V300 revert reasoning YTiling = 1 — in place NV12Enable = 1, GPU420Support = 1 — in place This confirms the V300 revert was the right call: FeatureControl is the origin, not a CRTCParams memory write. If DSC is still activated downstream despite DSCSupport=0, the investigation belongs in getDPCDInfo output or a later parsing step — not in a struct overwrite after the fact. Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850247 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) . Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850248 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) Powerwell struct + fix ghidra_seed_structs.h AppleIntelParams.hpp extract_apple_params.py structsFB.h Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850250 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850251 Share on other sites More sharing options...
jalavoui Posted May 13 Share Posted May 13 (edited) u can the power aproach. apple code is know to fail on sleep/wake calls 4 functions doing this if u can make it work u solve panel power issues and also a lot of apple code causing this {"__ZN21AppleIntelFramebuffer17prepareToExitWakeEv",dovoid}, {"__ZN21AppleIntelFramebuffer18prepareToExitSleepEv",dovoid}, {"__ZN21AppleIntelFramebuffer19prepareToEnterSleepEv",dovoid}, {"__ZN21AppleIntelFramebuffer18prepareToEnterWakeEv",dovoid} this code manages and calls all apple logic make it work and u might solve all issues i just remenbered that i hack this code a bit to force ws state 4 Edited May 13 by jalavoui 1 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850252 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 * All committed and pushed : restored fragmented-repeated screen, removed chip hack man in the middle V99R void Gen11::AppleIntelPowerWellinit(AppleIntel::AppleIntelPowerWell *that, AppleIntel::AppleIntelBaseController *param_1) { ccont = param_1->unk_0C40; FunctionCast(AppleIntelPowerWellinit, callback->oAppleIntelPowerWellinit)(that,param_1); } // V408: force linear tiling in the NEW (pl2) PLANEPARAMS before the comparison. // hwRegsNeedUpdate has no PLANEPARAMS argument — it cannot fix tiling there. // paramsSurfCompare is the last point where pl2 can be patched before its values // trigger raWriteRegister32 writes for PLANE_CTL and PLANE_STRIDE. // Old (pl1/hardware) is already linear from UEFI; patching pl2 to match suppresses // the X-tiled commit without any MMIO intercept. if (NGreen::callback && !NGreen::callback->isRealTGL && pl2) { pl2->PLANE_CTL = (pl2->PLANE_CTL & ~(0x7u << 10)); // bits[12:10] = 000 → linear pl2->PLANE_STRIDE = 0xa0; // 2560×4 / 64 = 160 = 0xa0 } Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850253 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) Key insights from the decomp: this+0x78 = fMMIO — same ccont value. Our hwSetPowerWellStatePGE/Aux/DDI already patch that+0x78 = ccont on every call, so the fixup is redundant there. this+0x18 = fAlwaysOn — if set, Apple calls overridePowerWellsState(this, true) at the end locking all wells permanently. For RPL/ADL this flag is likely never set since the controller flags at param_1+0x918 / param_1+0xc59 aren't what Apple expects. this+0x1c..+0x77 = PG/DDI/AUX state arrays — properly mapped now from the decomp. Our hwSetPowerWellStatePGE already completely replaces Apple's PGE logic for !isRealTGL, so overridePowerWellsState won't add much there. What we can do better: Update the AppleIntelPowerWell struct with the real field layout Log the raw register state (0x45404/0x45454/0x45444) at init time — tells us exactly what UEFI left enabled For !isRealTGL: force fAlwaysOn = 1 + force fMMIO = ccont as belt-and-suspenders after callthrough void Gen11::AppleIntelPowerWellinit(AppleIntel::AppleIntelPowerWell *that, AppleIntel::AppleIntelBaseController *param_1) { // Capture MMIO accessor before callthrough (param_1+0xC40 = fMMIO, stored at that+0x78). ccont = param_1->unk_0C40; // Log what UEFI left enabled in the three power well control registers. // This fires once at kext load and tells us the hardware's initial state. uint32_t pg = raReadRegister32(ccont, 0x45404); uint32_t ddi = raReadRegister32(ccont, 0x45454); uint32_t aux = raReadRegister32(ccont, 0x45444); SYSLOG("ngreen", "PowerWell::init UEFI state — PG=0x%08x DDI=0x%08x AUX=0x%08x", pg, ddi, aux); FunctionCast(AppleIntelPowerWellinit, callback->oAppleIntelPowerWellinit)(that, param_1); // Apple only sets fAlwaysOn if controller flags at +0x918 or +0xC59 are set. // Those flags are never set on RPL/ADL, so fAlwaysOn stays 0 and Apple is free // to disable power wells at runtime. Force it to 1 so that any subsequent // overridePowerWellsState call locks them always-on. // Also re-stamp fMMIO = ccont as belt-and-suspenders; the callthrough should have // done this but our ccont is the authoritative value captured before the call. if (!NGreen::callback->isRealTGL) { that->fAlwaysOn = 1; that->fMMIO = ccont; SYSLOG("ngreen", "PowerWell::init forced fAlwaysOn=1, fMMIO stamped"); } SYSLOG("ngreen", "PowerWell::init done — PG1=%u PG2=%u PG3=%u PG4=%u DDI[0]=%u AUX[0]=%u", that->fPG1, that->fPG2, that->fPG3, that->fPG4, that->fDDI[0], that->fAUX[0]); } // ─── Sleep/wake lifecycle hooks ────────────────────────────────────────────── // All four Apple implementations set this+0x49e0=4 as their final operation. // If Apple's code exits early (null Camellia ptr, lock contention, etc.) that // write never happens and the FB state machine is stuck. We callthrough and // then enforce state=4 regardless, plus track panel power for IOKit properties. // // Lifecycle order: // Sleep: prepareToEnterSleep → prepareToExitWake // Wake: prepareToExitSleep → prepareToEnterWake // Wake stage 2: confirm panel is on, log state. // Apple does: panel-power property, some vtable dispatch, then state=4. void Gen11::prepareToEnterWake(AppleIntel::AppleIntelFramebuffer *that) { uint32_t state_before = getMember<uint32_t>(that, 0x49e0); DBGLOG("ngreen", "prepareToEnterWake enter: fb=%p state=0x%x", that, state_before); bool panelOn = isPanelPowerOn(getMember<void *>(that, 0x1d0)); if (panelOn) { reinterpret_cast<IORegistryEntry *>(that)->setProperty("AAPL,LCD-PowerState-ON", true); } FunctionCast(prepareToEnterWake, callback->oprepareToEnterWake)(that); uint32_t state_after = getMember<uint32_t>(that, 0x49e0); if (state_after != 4) { SYSLOG("ngreen", "prepareToEnterWake: state=0x%x (expected 4), forcing", state_after); getMember<uint32_t>(that, 0x49e0) = 4; } DBGLOG("ngreen", "prepareToEnterWake exit: state=0x%x", getMember<uint32_t>(that, 0x49e0)); } // Sleep stage 2: NVRAM save, Camellia backlight off, StopTransactions, // disableDisplay, hwSetPanelPower(0), two handleEvent calls, then state=4. void Gen11::prepareToExitWake(AppleIntel::AppleIntelFramebuffer *that) { uint32_t state_before = getMember<uint32_t>(that, 0x49e0); DBGLOG("ngreen", "prepareToExitWake enter: fb=%p state=0x%x", that, state_before); reinterpret_cast<IORegistryEntry *>(that)->setProperty("AAPL,LCD-PowerState-ON", false); FunctionCast(prepareToExitWake, callback->oprepareToExitWake)(that); uint32_t state_after = getMember<uint32_t>(that, 0x49e0); if (state_after != 4) { SYSLOG("ngreen", "prepareToExitWake: state=0x%x (expected 4), forcing", state_after); getMember<uint32_t>(that, 0x49e0) = 4; } DBGLOG("ngreen", "prepareToExitWake exit: state=0x%x", getMember<uint32_t>(that, 0x49e0)); } // Sleep stage 1: fSleeping=1, cancel timers, clientNotify(2,0), state=4, // handleEvent(sleep), hwSaveState, hwDisableInterrupts, fGPUIsAwake=0. void Gen11::prepareToEnterSleep(AppleIntel::AppleIntelFramebuffer *that) { uint32_t state_before = getMember<uint32_t>(that, 0x49e0); DBGLOG("ngreen", "prepareToEnterSleep enter: fb=%p state=0x%x", that, state_before); reinterpret_cast<IORegistryEntry *>(that)->setProperty("AAPL,LCD-PowerState-ON", false); FunctionCast(prepareToEnterSleep, callback->oprepareToEnterSleep)(that); uint32_t state_after = getMember<uint32_t>(that, 0x49e0); if (state_after != 4) { SYSLOG("ngreen", "prepareToEnterSleep: state=0x%x (expected 4), forcing", state_after); getMember<uint32_t>(that, 0x49e0) = 4; } DBGLOG("ngreen", "prepareToEnterSleep exit: state=0x%x", getMember<uint32_t>(that, 0x49e0)); } // Wake stage 1: restorePowerWellsState, hwEnableInterrupts, hwInitializeCState, // hwRestoreState, probePortState per port, gamma/reg-cache restore, // clientNotify(2,1), handleEvent(wake), fGPUIsAwake=1, setDPPowerState, state=4. void Gen11::prepareToExitSleep(AppleIntel::AppleIntelFramebuffer *that) { uint32_t state_before = getMember<uint32_t>(that, 0x49e0); DBGLOG("ngreen", "prepareToExitSleep enter: fb=%p state=0x%x", that, state_before); FunctionCast(prepareToExitSleep, callback->oprepareToExitSleep)(that); uint32_t state_after = getMember<uint32_t>(that, 0x49e0); if (state_after != 4) { SYSLOG("ngreen", "prepareToExitSleep: state=0x%x (expected 4), forcing", state_after); getMember<uint32_t>(that, 0x49e0) = 4; } // fGPUIsAwake is at controller + 0x1a00 offset ((&DAT_00001a00)[ctrl]). // Apple sets it to 1 inside the callthrough; we track panel as on after wake. reinterpret_cast<IORegistryEntry *>(that)->setProperty("AAPL,LCD-PowerState-ON", true); DBGLOG("ngreen", "prepareToExitSleep exit: state=0x%x", getMember<uint32_t>(that, 0x49e0)); } Edited May 13 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850254 Share on other sites More sharing options...
Stezza88 Posted May 13 Author Share Posted May 13 (edited) . Edited May 14 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850255 Share on other sites More sharing options...
Stezza88 Posted May 14 Author Share Posted May 14 (edited) Commented these it pass the boot, now try to isolate stricter maybe only one is blocking uint32_t pg = raReadRegister32(ccont, 0x45404); uint32_t ddi = raReadRegister32(ccont, 0x45454); uint32_t aux = raReadRegister32(ccont, 0x45444); SYSLOG("ngreen", "PowerWell::init UEFI state — PG=0x%08x DDI=0x%08x AUX=0x%08x", pg, ddi, aux); New powerwell struct AppleIntelParams.hpp Edited May 14 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850256 Share on other sites More sharing options...
jalavoui Posted May 14 Share Posted May 14 (edited) note to ai: u dam blind bat fix structures so u can see this if u can't learn from nblue source i like the sleep/wake cycle. maybe do some tracing helps ? idea is simple try force a sleep-wake. trace calls. bugs will pop btw i forgot - check nred display fixs. for amd but some logic might apply Edited May 14 by jalavoui 1 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850257 Share on other sites More sharing options...
Stezza88 Posted May 14 Author Share Posted May 14 From the decompile and line 2994: this->contr = PowerWell's fController at +0x10 this->contr->flags_ig = AppleIntelBaseController field at +0xC58 (where we write FB_FLAG_BOOST_PIXEL_FREQUENCY_LIMIT) this->powerwellalwaysON = PowerWell's fAlwaysOn at +0x18 Two problems: flags_ig and fInfoFlags2 (at +0xC5C) are buried in the padding in AppleIntelBaseController - they need to be named fields fController in AppleIntelPowerWell is typed as void* so Ghidra can't trace through it Let me fix all of this plus add the tracing. Read kern_gen11.cpp (lines 3396-3445) Now I have the complete picture. The decompile is from AppleIntelPowerWell::init: this->contr = fController at +0x10 in the PowerWell this->contr->flags_ig = controller field at +0xC58 (where we write FB_FLAG_BOOST_PIXEL_FREQUENCY_LIMIT) this->powerwellalwaysON = fAlwaysOn at +0x18 in the PowerWell The bug implication: PowerWell::init sets fAlwaysOn only if flags_ig has FB_FLAG_BOOST_PIXEL_FREQUENCY_LIMIT set — but we set that flag in initPlatformWorkarounds, which may run after PowerWell::init. Here's a summary of what was done: Struct fixes (AppleIntelParams.hpp😞 Forward decl — struct AppleIntelBaseController; added before AppleIntelPowerWell so the PowerWell can type its controller pointer correctly. AppleIntelPowerWell::fController — changed from void* to AppleIntelBaseController* (Ghidra's name: contr). Now Ghidra can trace through it and show this->contr->flags_ig instead of *(uint32_t*)((char*)this->contr + 0xC58). fAlwaysOn — annotated with Ghidra's name powerwellalwaysON so the decompile maps cleanly. AppleIntelBaseController::flags_ig at +0xC58 — named and pulled out of the padding. This is the field the PowerWell init checks before setting fAlwaysOn. AppleIntelBaseController::fInfoFlags2 at +0xC5C — named (display feature flags). AppleIntelBaseController::fGPUIsAwake at +0x1A00 — named and pulled out of padding. static_asserts added for all three new controller fields. Code cleanup (kern_gen11.cpp😞 initPlatformWorkarounds now uses that->flags_ig / that->fInfoFlags2 instead of raw getMember<> offsets. Wrong +0xC59 comment in PowerWellinit corrected to +0xC58 and expanded to explain the fAlwaysOn dependency. PowerWell::init hook now logs flags_ig before the callthrough so you can see whether Apple's native path would have set fAlwaysOn. Sleep/wake tracing: All 4 lifecycle hooks now call logFBCtrlState() before and after the callthrough, logging: fbState, flags_ig, fInfoFlags2, fGPUIsAwake, pipe. Each sleep/wake cycle will print 8 SYSLOG lines — if the GPU isn't waking, fGPUIsAwake will stay 0 after prepareToExitSleep<< and the bug is immediately visible. Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850258 Share on other sites More sharing options...
Stezza88 Posted May 14 Author Share Posted May 14 (edited) x.log.zip fb.log Edited May 14 by Stezza88 Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850260 Share on other sites More sharing options...
Stezza88 Posted May 14 Author Share Posted May 14 Here's the full analysis: Register reads (0x45404/0x45454/0x45444) — working, no hang Raw PG=0x0000fc0f decoded: bit 0 = PG1 request = 1 ✓ bit 1 = PG1 state = 1 ✓ (always-on domain up) bit 2 = PG2 request = 1 bit 3 = PG2 state = 1 (PG2 is actually ON in hardware) bits 10-15 = all 1 (TC/additional wells) Problem: Apple parsed fPG2=0 despite hardware showing PG2=on The raw register at 0x45404 shows bits 2,3 both set (PG2 enabled), but Apple's callthrough wrote fPG2=0. This is an ADL-P vs TGL bit-layout mismatch — Apple's TGL PowerWell::init interprets bit positions for TGL's power well ID table, not ADL-P's. On ADL-P, those same bits map to different domain IDs. Not critical — fAlwaysOn=1 makes overridePowerWellsState lock all wells on regardless. DDI — correct DDI=0x00000003 → bits 0,1 = DDI_A request+state = enabled → fDDI[0]=1 ✓ Internal panel port A recognized. Nothing else needed on a laptop. AUX — register address mismatch, not real problem AUX=0x00000000 from 0x45444 — but line 97 shows AUX transactions work: V97AUX[1] ret=0x0 [0]=0x14 [1]=0x1e 0x45444 is a TGL-specific AUX control register address; on ADL-P that offset maps to something else. The AUX power path on ADL-P is different. flags_ig=0x0 — confirms hook is load-bearing fAlwaysOn(before)=0 — Apple would have left power wells ungated without our forced fAlwaysOn=1. Hook is doing its job. V101/V102 — power well state changed after init During PowerWell::init: 0x45404 = 0xfc0f (PG2 on) After DMC load (V101): CTL2 = 0xc03 → PG2 now off, only PG1+higher bits remain Expected — the ADL-P DMC takes over power gating after load and puts the display into DC5/DC6. With fAlwaysOn=1, Apple's layer should re-enable wells on demand. Summary: PowerWell init data is correct. fMMIO valid, fAlwaysOn forced, PG1+DDI_A confirmed active. The fPG2=0 discrepancy is a TGL/ADL-P register map difference but irrelevant with fAlwaysOn=1 in place. Lilu_1.7.2_23.6.txt Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850261 Share on other sites More sharing options...
Stezza88 Posted May 14 Author Share Posted May 14 The Lilu log doesn't show any V103p messages (no DC_STATE_EN writes during the captured early-boot window). But that's expected — the write likely happens after WindowServer starts. The timeline would be: Boot → NootedGreen loads ADL-P DMC ✓ TGL FB kext initializes, display comes up (EFI gray) ✓ WindowServer starts, writes DC_STATE_EN (enters DC3/DC5/DC6) ADL-P DMC takes over display power management Apple's ICL-targeted kext has no ADL-P DC-exit recovery path eDP lanes drop → black screen The display is configured correctly (all V401/V97C/V97P logs look healthy), so the black screen isn't a pipeline config problem — it's DC state entry with no exit. Two things to verify and decide: Option A — Quick isolation test: boot with ngreen-dmc=adlp disabled temporarily. If the display comes back, the DMC + unblocked DC_STATE_EN is confirmed as the cause. Option B — Re-enable V103 as a known-working baseline: it was removed as a "symptom-hiding hack" per jalavoui's guidance, but it kept the display working. Before pursuing a proper DC-exit implementation, confirm this IS the cause first. The proper fix (what the comment points at): implement ADL-P DC-exit handling in NootedGreen. Linux i915 does this via intel_display_power.c — specifically gen9_disable_dc_states() / gen12_disable_dc_states() which re-enable the power wells and restore the display state when DC6 exits. The NootedGreen equivalent would be hooking whatever Apple's driver calls when it wants to resume from low power, and doing the ADL-P-specific register dance before returning. Is the black screen persistent from first pixel, or does it briefly show content then go dark? Black from the very first pixel means the DMC enters DC5/DC6 during init (before WindowServer), not after 70s. The comment at line 3328-3331 is the key: "The ADL-P DMC firmware (even correct binary) autonomously drops all eDP lanes at ~10s because its DC state management code runs on ADL-P hardware and performs link maintenance that the ICL driver can't recover from." And V103P (the periodic DC_STATE_EN=0 tick) was removed alongside V103. Now I have everything I need. Here's the plan: Add adlpDcExit(const char *caller) to NGreen — runs the full ADL-P power domain restore when DC state is detected Call it from hwRegsNeedUpdate (before any register writes fire) and from the V60 tick (replacing the removed V103Pp) The V103/V103F passthrough sites stay as-is (already logging) The restore sequence mirrors the hwInitCState ADL-P path: DC_STATE_EN=0 → power wells → 8Fxxx context regs → PSR disable. Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850263 Share on other sites More sharing options...
jalavoui Posted May 14 Share Posted May 14 (edited) no comments. just picture howto find a var name ? sample here same for var type uint32 = undefined4 or signed int if in code note the bug at pg1 (maybe int or all others are unsigned) ask the bot todo something usefull like rebuild vtables in short this strucutures better not be in ngren cause if 1 field is wrong u get a ton of bugs this mean bot can't see it's on top of function powerwell::init worst it can't map osinfo flags and propagate in entire code analysys will be weak or missleading note to ai: u're fired Edited May 14 by jalavoui Link to comment https://www.insanelymac.com/forum/topic/362634-nootedgreenkext-is-on-air-its-a-long-long-road-to-complete/page/17/#findComment-2850264 Share on other sites More sharing options...
Recommended Posts