/** * 010 Editor v8.0.1 Binary Template * * File: Intel Framebuffer kexts from 10.13.3 * Authors: vit9696 * Version: 0.6 * Purpose: Intel Framebuffer decoding * * Copyright (c) 2018 vit9696 * * Thanks to bcc9, Piker-Alpha, joevt and all the others who reversed Intel Framebuffer code. */ LittleEndian(); /* There is various not so accurate information but it is worth checking: * http://www.insanelymac.com/forum/topic/259705-editing-custom-connectorinfo-for-intel-hd-3000-graphics-sandy-bridge-osx-lion/ * https://github.com/Piker-Alpha/AppleIntelFramebufferAzul.sh/blob/master/AppleIntelFramebufferAzul.sh * https://www.tonymacx86.com/threads/skylake-intel-hd-530-integrated-graphics-working-as-of-10-11-4.188891/page-29#post-1297155 * https://pikeralpha.wordpress.com/2013/08/02/appleintelframebufferazul-kext-part-ii/ */ /** * Please note, that CFL and onwards are in a very draft state, and may contain partially invalid data!!! */ typedef unsigned char uint8_t; typedef uint16 uint16_t; typedef uint32 uint32_t; typedef uint64 uint64_t; typedef char int8_t; typedef int16 int16_t; typedef int32 int32_t; typedef int64 int64_t; enum <uint32_t> FirstFramebuffer { FirstSandyBridgeId = 0x00040201, /* note, this is just a marker */ DefSandyBridgeId = 0x00010200, /* note, this is just a marker */ FirstIvyBridgeId = 0x01660000, FirstHaswellId = 0x0c060000, FirstBroadwellId = 0x16060000, FirstSkylakeId = 0x191e0000, FirstKabyLakeId = 0x591e0000, FirstCoffeeLakeId = 0x3ea50009, FirstCannonLakeId = 0x5a510009, FirstIceLakeId = 0xff050000, /* LP and HP share the table */ }; enum <uint32_t> CamelliaVersion { CamelliaDisabled = 0, /* -nocam */ CamelliaV1 = 1, /* -forcecam1 */ CamelliaV2 = 2, /* -forcecam2, CamelliaTcon2 */ CamelliaV3 = 3, /* BanksiaTcon */ CamelliaUnsupported = 0xFF /* dummy value for snb */ }; union FramebufferFlags { struct FramebufferFlagBits { /* Discovered in AppleIntelFBController::LinkTraining. Disables the use of FastLinkTraining. * According to joevt with zero SKL link training happens at 450 MHz else at 540 MHz */ uint8_t FBAvoidFastLinkTraining :1; /* 0x1 */ /* Sets the logic of minStolenMem calculation, when set fStolenMemorySize is not multiplied * by fFBMemoryCount, assuming fStolenMemorySize counts all framebuffers at once. */ uint8_t FBFramebufferCommonMemory :1; /* 0x2 */ /* Discovered in AppleIntelFramebufferController::getFeatureControl. * This is equivalent to setting FBC=1 in the plist FeatureControl section. * Compression causes fFramebufferMemorySize to be added to minStolenMem. */ uint8_t FBFramebufferCompression :1; /* 0x4 */ /* Discovered in AppleIntelFramebufferController::getFeatureControl. * This is equivalent to setting SliceSDEnable=1, EUSDEnable=1, DynamicSliceSwitch=1 in the plist FeatureControl section. */ uint8_t FBEnableSliceFeatures :1; /* 0x8 */ /* Discovered in AppleIntelFramebufferController::getFeatureControl. * This is equivalent to setting DynamicFBCEnable=1 in the plist FeatureControl section. */ uint8_t FBDynamicFBCEnable :1; /* 0x10 */ /* This sets fUseVideoTurbo=1 and loads GPU turbo frequency from the specific field. * Defaults to 14, can be overridden by VideoTurboFreq in the plist FeatureControl section. */ uint8_t FBUseVideoTurbo :1; /* 0x20 */ /* Discovered in AppleIntelFramebuffer::getDisplayStatus. * Enforces display power reset even on always connected displays (see connector flags CNConnectorAlwaysConnected). */ uint8_t FBForcePowerAlwaysConnected :1; /* 0x40 */ /* According to joevt this enforces High Bitrate mode 1, which limits DP bitrate to 8.64 Gbit/s instead of normal 17.28 Gbit/s (HBR2). * I do not think this is used on Skylake any longer. */ uint8_t FBDisableHighBitrateMode2 :1; /* 0x80 */ /* This bit is not used on Broadwell and newer but set when fPortCount > 0, i.e. for all online framebuffers. * On Haswell it is used by AppleIntelFramebuffer::GetOnlineInfo and is set only on 0x0D260007 (MacBookPro11,3) and 0x0D26000E, which are top models. * This appears to boost pixel frequency limit (aka pixel clock) to 540000000 Hz (from the usual 216000000, 320000000, 360000000, 450000000). */ uint8_t FBBoostPixelFrequencyLimit :1; /* 0x100 */ /* Discovered in AppleIntelFramebuffer::ValidateSourceSize. * Limits source size to 4096x4096. */ uint8_t FBLimit4KSourceSize :1; /* 0x200 */ /* Discovered in AppleIntelFramebufferController::start. * These bits appear to be entirely equivalent and could be used interchangeably. Result in setting: * - PCH_LP_PARTITION_LEVEL_DISABLE (1 << 12) bit in SOUTH_DSPCLK_GATE_D (0xc2020) * - LPT_PWM_GRANULARITY (1 << 5) bit in SOUTH_CHICKEN2 (0xc2004) * See Linux driver sources (lpt_init_clock_gating, lpt_enable_backlight). * Since these bits are setting backlight pulse width modularity, there is no sense in setting them without a built-in display (i.e. on desktop). */ uint8_t FBAlternatePWMIncrement1 :1; /* 0x400 */ uint8_t FBAlternatePWMIncrement2 :1; /* 0x800 */ /* Discovered in Broadwell AppleIntelFBController::start / AppleIntelFBController::getFeatureControl. * This is equivalent to setting DisableFeatureIPS=1 in the plist FeatureControl section. * IPS stands for Intermediate Pixel Storage */ uint8_t FBDisableFeatureIPS :1; /* 0x1000 */ uint8_t FBUnknownFlag_2000 :1; /* 0x2000 */ /* Discovered in Broadwell AppleIntelFBController::getOSInformation. * Used by AppleIntelFramebufferController::LinkTraining for camellia version 2. * Can be overridden by -notconrecover boot-arg, which effectively unsets this bit. */ uint8_t FBAllowConnectorRecover :1; /* 0x4000 */ uint8_t FBUnknownFlag_8000 :1; /* 0x8000 */ uint8_t FBUnknownFlag_10000 :1; /* 0x10000 */ uint8_t FBUnknownFlag_20000 :1; /* 0x20000 */ /* Discovered in AppleIntelFramebufferController::getFeatureControl. * This takes its effect only if GFMPPFM in the plist FeatureControl section is set to 2, otherwise GFMPPFM is off. */ uint8_t FBDisableGFMPPFM :1; /* 0x40000 */ uint8_t FBUnknownFlag_80000 :1; /* 0x80000 */ uint8_t FBUnknownFlag_100000 :1; /* 0x100000 */ /* Discovered in AppleIntelFramebufferController::getFeatureControl. * This takes its effect only if SupportDynamicCDClk in the plist FeatureControl section is set to 1, otherwise off. * Also requires dc6config to be set to 3 (default). */ uint8_t FBEnableDynamicCDCLK :1; /* 0x200000 */ uint8_t FBUnknownFlag_400000 :1; /* 0x400000 */ /* Discovered in AppleIntelFramebuffer::enableController. * Used by AppleIntelFramebuffer::ValidateSourceSize. * Setting this bit increases the maximum source size from 4096x4096 to 5120x5120. * Most likely this enables 5K support via Intel HD. */ uint8_t FBSupport5KSourceSize :1; /* 0x800000 */ uint8_t FBUknownZeroFlags; Assert(FBUknownZeroFlags == 0, "FBUknownZeroFlags are not zero, new flags were added!"); } bits; uint32_t value; }; /* This is the same as ATI/AMD code. * At this moment only 2, 4, 0x400, and 0x800 are somewhat supported. * Interestingly connector type is not so important nowadays, e.g. VGA works fine on Kaby on DP. * As of SKL and newer ConnectorType is converted to fPortType by the following algo: * - connector with zero index (LVDS) gets fPortType 3. * - connector with ConnectorHDMI type gets fPortType 1. * - otherwise a connector has fPortType 2 (DisplayPort-like). */ enum <uint32_t> ConnectorType { ConnectorZero = 0x0, ConnectorDummy = 0x1, /* Always used as dummy, seems to sometimes work as VGA */ ConnectorLVDS = 0x2, /* Just like on AMD LVDS is used for eDP */ ConnectorDigitalDVI = 0x4, /* This is not eDP despite a common misbelief */ ConnectorSVID = 0x8, ConnectorVGA = 0x10, ConnectorDP = 0x400, ConnectorHDMI = 0x800, ConnectorAnalogDVI = 0x2000 }; /* I can see very few mentioned in the code (0x1, 0x8, 0x40), though connectors themselves define way more! */ union ConnectorFlags { struct ConnectorFlagBits { /* Bits 1, 2, 8 are mentioned in AppleIntelFramebufferController::GetGPUCapability */ /* Lets apperture memory to be not required AppleIntelFramebuffer::isApertureMemoryRequired */ uint8_t CNAlterAppertureRequirements :1; /* 0x1 */ uint8_t CNUnknownFlag_2 :1; /* 0x2 */ uint8_t CNUnknownFlag_4 :1; /* 0x4 */ /* Normally set for LVDS displays (i.e. built-in displays) */ uint8_t CNConnectorAlwaysConnected :1; /* 0x8 */ /* AppleIntelFramebuffer::maxSupportedDepths checks this and returns 2 IODisplayModeInformation::maxDepthIndex ?? */ uint8_t CNUnknownFlag_10 :1; /* 0x10 */ uint8_t CNUnknownFlag_20 :1; /* 0x20 */ /* Disable blit translation table? AppleIntelFramebufferController::ConfigureBufferTranslation */ uint8_t CNDisableBlitTranslationTable:1; /* 0x40 */ /* Used in AppleIntelFramebufferController::setPowerWellState */ /* Activates MISC IO power well (SKL_DISP_PW_MISC_IO) */ uint8_t CNUseMiscIoPowerWell :1; /* 0x80 */ /* Used in AppleIntelFramebufferController::setPowerWellState */ /* Activates Power Well 2 usage (SKL_PW_CTL_IDX_PW_2) */ /* May help with HDMI audio configuration issues */ /* REF: https://github.com/acidanthera/bugtracker/issues/1189 */ uint8_t CNUsePowerWell2 :1; /* 0x100 */ uint8_t CNUnknownFlag_200 :1; /* 0x200 */ uint8_t CNUnknownFlag_400 :1; /* 0x400 */ /* Sets fAvailableLaneCount to 30 instead of 20 when specified */ uint8_t CNIncreaseLaneCount :1; /* 0x800 */ uint8_t CNUnknownFlag_1000 :1; /* 0x1000 */ uint8_t CNUnknownFlag_2000 :1; /* 0x2000 */ uint8_t CNUnknownFlag_4000 :1; /* 0x4000 */ uint8_t CNUnknownFlag_8000 :1; /* 0x8000 */ uint16_t CNUnknownZeroFlags; Assert(CNUnknownZeroFlags == 0, "CNUnknownZeroFlags are not zero, new flags were added!"); } bits; uint32_t value; }; struct ConnectorInfo { /* Watch out, this is really messy (see AppleIntelFramebufferController::MapFBToPort). * I am not fully sure why this exists, and recommend setting index to array index (i.e. the sequential number from 0). * * The only accepted values are 0, 1, 2, 3, and -1 (0xFF). When index is equal to array index the logic is simple: * Port with index 0 is always considered built-in (of LVDS type) regardless of any other values. * Ports with indexes 1~3 are checked against type, HDMI will allow the use of digital audio, otherwise DP is assumed. * Port with index 0xFF is ignored and skipped. * * When index != array index port type will be read from connector[index].type. * Say, we have 2 active ports: * 0 - [1] busId 4 type LVDS * 1 - [2] busId 5 type DP * 2 - [3] busId 6 type HDMI * 3 - [-1] busId 0 type Dummy * This will result in 2 framebuffers which types will be shifted: * 0 - busId 4 type DP * 1 - busId 5 type HDMI * In fact BusId values are also read as connector[index].busId, but are later mapped back via * AppleIntelFramebufferController::getGMBusIDfromPort by looking up a connector with the specified index. * The lookup will stop as soon as a special marker connector (-1) is found. To illustrate, if we have 2 active ports: * 0 - [1] busId 4 type LVDS * 1 - [2] busId 5 type DP * 2 - [-1] busId 6 type HDMI * 3 - [-1] busId 0 type Dummy * The result will be 2 framebuffers which types and the second busId will be shifted: * 0 - busId 4 type DP * 1 - busId 6 type HDMI * It is also used for port-number calculation. * - LVDS displays (more precisely, displays with CNConnectorAlwaysConnected flag set) get port-number 0. * - Other displays go through index - port-number mapping: 1 - 5, 2 - 6, 3 - 7, or fallback to 0. */ uint8_t index; /* Proven by AppleIntelFramebufferController::MapFBToPort, by a call to AppleIntelFramebufferController::getGMBusIDfromPort. * This is GMBUS (Graphic Management Bus) ID described in https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-hsw-display_0.pdf. * The use could be found in Intel Linux Graphics Driver source code: * https://github.com/torvalds/linux/blob/6481d5ed076e69db83ca75e751ad492a6fb669a7/drivers/gpu/drm/i915/intel_i2c.c#L43 * https://github.com/torvalds/linux/blob/605dc7761d2701f73c17183649de0e3044609817/drivers/gpu/drm/i915/i915_reg.h#L3053 * However, it should be noted that Apple identifiers are slightly different from Linux driver. * In Linux 0 means disabled, however, for Apple it has some special meaning and is used for internal display. * Other than that the values are the same: * - GMBUS_PIN_DPC (4) HDMIC * - GMBUS_PIN_DPB (5) SDVO, HDMIB * - GMBUS_PIN_DPD (6) HDMID * - GMBUS_PIN_VGADDC (2) VGA until Broadwell inclusive. * So basically you could use 4, 5, 6 for arbitrary HDMI or DisplayPort displays. * Since 5 supports SDVO (https://en.wikipedia.org/wiki/Serial_Digital_Video_Out), it may also be used to support DVI displays. * Starting with Skylake VGA works via SDVO too (instead of a dedicated GMBUS_PIN_VGADDC id). */ uint8_t busId; /* Appears to be used for grouping ports just like Piker says, but I cannot find the usage. */ uint8_t pipe; uint8_t pad; Assert(pad == 0, "Non-zero padding"); ConnectorType type <read=connectorTypeToPrintable>; /* These are connector flags, they have nothing to do with delays regardless of what Piker says. * I tried to describe some in ConnectorFlags. */ ConnectorFlags flags <read=connectorFlagsToPrintable>; }; /* Wide connector type format */ struct ConnectorInfoICL { uint32_t index; uint32_t busId; uint32_t pipe; uint32_t pad; ConnectorType type <read=connectorTypeToPrintable>; ConnectorFlags flags <read=connectorFlagsToPrintable>; }; /* It should be noted that some displays use more than 1 pipe, so maxPipes != maxDisplays. */ struct FramebufferSNB { local uint32_t framebufferId = 0; local string framebufferStr = ""; uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; /* also fNumFramebuffer */ uint8_t fFBMemoryCount; /* 0 means unused. */ uint32_t fBacklightFrequency; uint32_t fBacklightMax; ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; local uint32_t fStolenMemorySize = 0; local uint32_t fFramebufferMemorySize = 0; local uint32_t fUnifiedMemorySize = 0; local uint8_t camelliaVersion = CamelliaUnsupported; local uint32_t flags = 0; local uint64_t fModelNameAddr = 0; }; string frameIdFromIndex(uint32_t frame, uint32_t index) { local string out; if (frame != 0) { /* Ivy and newer */ SPrintf(out, "%08X", frame); } else { /* Sandy Bridge has stupid frame detection logic. * See board-id list below, which enable framebuffer fallbacks. */ switch (index) { case 0: out="SNB0 0x10000"; break; case 1: out="SNB1 0x20000"; break; case 2: out="SNB2 0x30010 or 0x30020"; break; case 3: out="SNB3 0x30030"; break; case 4: out="SNB4 0x40000"; break; case 5: out="SNB5 0x50000"; break; case 6: out="SNB6 Not addressible"; break; case 7: out="SNB7 Not addressible"; break; /* There are 8 frames for sandy aside the default one, but only the first 6 are addressible. */ default: out="Error"; } } return out; } struct FramebufferIVB { uint32_t framebufferId; uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; /* also fNumFramebuffer */ uint8_t fFBMemoryCount; uint32_t fStolenMemorySize <read=bytesToPrintable>; uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t fBacklightFrequency <read=frequencyToPrintable>; uint32_t fBacklightMax <read=frequencyToPrintable>; uint32_t unk1[2]; uint32_t unk2[2]; uint32_t unk3; ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; uint32_t pad2[26]; local uint8_t camelliaVersion = CamelliaUnsupported; local uint32_t flags = 0; local uint64_t fModelNameAddr = 0; }; /* Some names are taken from 10.9 Azul driver. While they may not be the same names used in the struct, they are handy at least. */ struct FramebufferHSW { uint32_t framebufferId; uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; /* also fNumFramebuffer */ uint8_t fFBMemoryCount; uint32_t fStolenMemorySize <read=bytesToPrintable>; uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fCursorMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t fBacklightFrequency <read=frequencyToPrintable>; uint32_t fBacklightMax <read=frequencyToPrintable>; uint32_t pad[2]; Assert(pad[0] == 0 && pad[1] == 0, "Non-zero padding"); ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; uint8_t unk1[3]; uint8_t camelliaVersion <read=camelliaToPrintable>; uint32_t unk2; uint32_t fNumTransactionsThreshold; uint32_t fVideoTurboFreq; uint32_t unk3; local uint64_t fModelNameAddr = 0; }; struct FramebufferBDW { uint32_t framebufferId; uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; uint32_t fStolenMemorySize <read=bytesToPrintable>; uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t fBacklightFrequency <read=frequencyToPrintable>; uint32_t fBacklightMax <read=frequencyToPrintable>; uint32_t pad[3]; Assert(pad[0] == 0 && pad[1] == 0 && pad[2] == 0, "Non-zero padding"); ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; uint32_t unk1; uint32_t camelliaVersion <read=camelliaToPrintable>; uint32_t unk2[6]; uint32_t fNumTransactionsThreshold; uint32_t fVideoTurboFreq; uint32_t fRC6_Threshold; local uint64_t fModelNameAddr = 0; }; struct FramebufferSKL { uint32_t framebufferId; /* Unclear what values really are, yet 4 stands for non-LP chipset. * See AppleIntelFramebufferController::start. */ uint32_t fPchType; Assert(fPchType == 0, "Non-zero PCH type"); uint64_t fModelNameAddr <read=modelNameAddrToPrintable>; /* While it is hard to be sure, because having 0 here results in online=true returned by * AppleIntelFramebuffer::GetOnlineInfo, after all it appears to be the case, and the unused * so-called mobile framebufers are simply set to fail-safe defaults. * For some reason it is often called fDisabled... */ uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; /* This one is per framebuffer fStolenMemorySize * fFBMemoryCount */ uint32_t fStolenMemorySize <read=bytesToPrintable>; /* This is for boot framebuffer from what I can understand */ uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t fBacklightFrequency <read=frequencyToPrintable>; uint32_t fBacklightMax <read=frequencyToPrintable>; uint32_t pad1[2]; Assert(pad1[0] == 0 && pad1[1] == 0, "Non-zero sequence"); ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; /* Check DDI Buffer Translations in Linux driver for details. */ uint8_t fBTTableOffsetIndexSlice; /* FBEnableSliceFeatures = 1 */ uint8_t fBTTableOffsetIndexNormal; /* FBEnableSliceFeatures = 0 */ uint8_t fBTTableOffsetIndexHDMI; /* fDisplayType = 1 */ uint8_t pad2; Assert(pad2 == 0, "Non-zero sequence"); uint32_t camelliaVersion <read=camelliaToPrintable>; uint64_t unk3[3]; uint32_t fNumTransactionsThreshold; /* Defaults to 14, used when UseVideoTurbo bit is set */ uint32_t fVideoTurboFreq; uint32_t pad3; Assert(pad3 == 0, "Non-zero sequence"); uint64_t fBTTArraySliceAddr; uint64_t fBTTArrayNormalAddr; uint64_t fBTTArrayHDMIAddr; uint32_t fSliceCount; uint32_t fEuCount; uint32_t unk6[2]; }; struct FramebufferCFL { uint32_t framebufferId; /* Unclear what values really are, yet 4 stands for non-LP chipset. * See AppleIntelFramebufferController::start. */ uint32_t fPchType; Assert(fPchType == 0, "Non-zero PCH type"); uint64_t fModelNameAddr <read=modelNameAddrToPrintable>; /* While it is hard to be sure, because having 0 here results in online=true returned by * AppleIntelFramebuffer::GetOnlineInfo, after all it appears to be the case, and the unused * so-called mobile framebufers are simply set to fail-safe defaults. * For some reason it is often called fDisabled... */ uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; /* This one is per framebuffer fStolenMemorySize * fFBMemoryCount */ uint32_t fStolenMemorySize <read=bytesToPrintable>; /* This is for boot framebuffer from what I can understand */ uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t pad1[2]; Assert(pad1[0] == 0 && pad1[1] == 0, "Non-zero sequence"); ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; /* Check DDI Buffer Translations in Linux driver for details. */ uint8_t fBTTableOffsetIndexSlice; /* FBEnableSliceFeatures = 1 */ uint8_t fBTTableOffsetIndexNormal; /* FBEnableSliceFeatures = 0 */ uint8_t fBTTableOffsetIndexHDMI; /* fDisplayType = 1 */ uint8_t pad2; Assert(pad2 == 0, "Non-zero sequence"); uint32_t camelliaVersion <read=camelliaToPrintable>; uint64_t unk3[3]; uint32_t fNumTransactionsThreshold; /* Defaults to 14, used when UseVideoTurbo bit is set */ uint32_t fVideoTurboFreq; uint32_t pad3; Assert(pad3 == 0, "Non-zero sequence"); uint64_t fBTTArraySliceAddr; uint64_t fBTTArrayNormalAddr; uint64_t fBTTArrayHDMIAddr; uint32_t fSliceCount; uint32_t fEuCount; uint32_t unk6[2]; local uint32_t fBacklightFrequency <read=frequencyToPrintable> = 0 ; local uint32_t fBacklightMax <read=frequencyToPrintable> = 0; }; /* Not sure what it is, in CNL value2 is a pointer, and value1 could be size. */ struct FramebufferCNLCurrents { uint32_t value1; uint32_t pad; uint64_t valu2; }; struct FramebufferCNL { uint32_t framebufferId; /* Unclear what values really are, yet 4 stands for non-LP chipset. * See AppleIntelFramebufferController::start. */ uint32_t fPchType; Assert(fPchType == 0, "Non-zero fPchType"); uint64_t fModelNameAddr <read=modelNameAddrToPrintable>; /* While it is hard to be sure, because having 0 here results in online=true returned by * AppleIntelFramebuffer::GetOnlineInfo, after all it appears to be the case, and the unused * so-called mobile framebufers are simply set to fail-safe defaults. * For some reason it is often called fDisabled... */ uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; /* This one is per framebuffer fStolenMemorySize * fFBMemoryCount */ uint32_t fStolenMemorySize <read=bytesToPrintable>; /* This is for boot framebuffer from what I can understand */ uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t pad1[2]; Assert(pad1[0] == 0 && pad1[1] == 0, "Non-zero sequence"); ConnectorInfo connectors[4] <read=connectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; /* Check DDI Buffer Translations in Linux driver for details. */ uint8_t fBTTableOffsetIndexSlice; /* FBEnableSliceFeatures = 1 */ uint8_t fBTTableOffsetIndexNormal; /* FBEnableSliceFeatures = 0 */ uint8_t fBTTableOffsetIndexHDMI; /* fDisplayType = 1 */ uint8_t pad2; Assert(pad2 == 0, "Non-zero sequence"); uint64_t unk1[5]; uint64_t fBTTArraySliceAddr; uint64_t fBTTArrayNormalAddr; uint64_t fBTTArrayHDMIAddr; FramebufferCNLCurrents currents[8]; uint32_t camelliaVersion <read=camelliaToPrintable>; uint64_t unk2[3]; uint32_t fNumTransactionsThreshold; /* Defaults to 14, used when UseVideoTurbo bit is set */ uint32_t fVideoTurboFreq; uint32_t fSliceCount; uint32_t fEuCount; uint32_t unk4; uint32_t unk5[2]; local uint32_t fBacklightFrequency <read=frequencyToPrintable> = 0 ; local uint32_t fBacklightMax <read=frequencyToPrintable> = 0; }; struct FramebufferICLHP { uint32_t framebufferId; /* Unclear what values really are, yet 4 stands for non-LP chipset. * See AppleIntelFramebufferController::start. */ uint32_t fPchType; uint64_t fModelNameAddr <read=modelNameAddrToPrintable>; /* While it is hard to be sure, because having 0 here results in online=true returned by * AppleIntelFramebuffer::GetOnlineInfo, after all it appears to be the case, and the unused * so-called mobile framebufers are simply set to fail-safe defaults. * For some reason it is often called fDisabled... */ uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; /* This one is per framebuffer fStolenMemorySize * fFBMemoryCount */ uint32_t fStolenMemorySize <read=bytesToPrintable>; /* This is for boot framebuffer from what I can understand */ uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; uint32_t fBacklightFrequency <read=frequencyToPrintable>; uint32_t fBacklightMax <read=frequencyToPrintable>; uint32_t pad1[2]; Assert(pad1[0] == 0 && pad1[1] == 0, "Non-zero sequence"); ConnectorInfoICL connectors[3] <read=wideConnectorToPrintable, optimize=false>; FramebufferFlags flags <read=framebufferFlagsToPrintable>; FramebufferCNLCurrents currents[8]; uint32_t unk2[5]; uint32_t camelliaVersion <read=camelliaToPrintable>; uint32_t unk3[6]; /* Defaults to 14, used when UseVideoTurbo bit is set */ uint32_t fNumTransactionsThreshold; uint32_t fVideoTurboFreq; uint32_t fSliceCount; uint32_t fEuCount; uint32_t unk4; }; struct FramebufferICLLP { uint32_t framebufferId; /* Unclear what values really are, yet 4 stands for non-LP chipset. * See AppleIntelFramebufferController::start. */ uint32_t fPchType; uint64_t fModelNameAddr <read=modelNameAddrToPrintable>; /* While it is hard to be sure, because having 0 here results in online=true returned by * AppleIntelFramebuffer::GetOnlineInfo, after all it appears to be the case, and the unused * so-called mobile framebufers are simply set to fail-safe defaults. * For some reason it is often called fDisabled... */ uint8_t fMobile; uint8_t fPipeCount; uint8_t fPortCount; uint8_t fFBMemoryCount; /* This one is per framebuffer fStolenMemorySize * fFBMemoryCount */ uint32_t fStolenMemorySize <read=bytesToPrintable>; /* This is for boot framebuffer from what I can understand */ uint32_t fFramebufferMemorySize <read=bytesToPrintable>; uint32_t fUnifiedMemorySize <read=bytesToPrintable>; ConnectorInfoICL connectors[6] <optimize=false>; /* Flags are quite different in ICL now */ uint32_t flags; uint32_t unk2; FramebufferCNLCurrents currents[3]; uint32_t unk3[2]; uint32_t camelliaVersion <read=camelliaToPrintable>; uint32_t unk4[3]; uint32_t fNumTransactionsThreshold; /* Defaults to 14, used when UseVideoTurbo bit is set */ uint32_t fVideoTurboFreq; uint32_t fSliceCount; uint32_t fEuCount; uint32_t unk5; uint8_t unk6; uint8_t pad[3]; local uint32_t fBacklightFrequency <read=frequencyToPrintable> = 0 ; local uint32_t fBacklightMax <read=frequencyToPrintable> = 0; }; uint32_t calculateStolenHaswell(FramebufferFlags &flags, uint32_t fStolenMemorySize, uint32_t fFBMemoryCount, uint32_t fFramebufferMemorySize) { local uint32_t fTotalStolen = 0x100000; /* a constant */ if (flags.bits.FBFramebufferCommonMemory) /* formerly FBUnknownFlag_2 */ fTotalStolen += fStolenMemorySize; else fTotalStolen += fStolenMemorySize * fFBMemoryCount; /* Prior to Skylake fFramebufferMemorySize is taken into account unconditionally */ fTotalStolen += fFramebufferMemorySize; return fTotalStolen; } uint32_t calculateStolenSkylake(FramebufferFlags &flags, uint32_t fStolenMemorySize, uint32_t fFBMemoryCount, uint32_t fFramebufferMemorySize) { local uint32_t fTotalStolen = 0x100000; /* a constant */ if (flags.bits.FBFramebufferCommonMemory) /* formerly FBUnknownFlag_2 */ fTotalStolen += fStolenMemorySize; else fTotalStolen += fStolenMemorySize * fFBMemoryCount; if (flags.bits.FBFramebufferCompression) fTotalStolen += fFramebufferMemorySize; return fTotalStolen; } uint32_t calculateStolenIceLake(uint32_t flags, uint32_t fStolenMemorySize, uint32_t fFBMemoryCount, uint32_t fFramebufferMemorySize) { local uint32_t fTotalStolen = 0x100000; /* a constant */ if (flags & 0x2 /* FBFramebufferCommonMemory */) fTotalStolen += fStolenMemorySize; else fTotalStolen += fStolenMemorySize * fFBMemoryCount; if (flags & 0x4 /* FBFramebufferCompression */) fTotalStolen += fFramebufferMemorySize; return fTotalStolen; } string bytesToPrintable(uint32_t bytes) { local string out; if (bytes >= 1024*1024) { if (bytes % (1024*1024) == 0) { SPrintf(out, "%d MB", bytes/1024/1024); } else { SPrintf(out, "%d MB (%d bytes)", bytes/1024/1024, bytes); } } else if (bytes >= 1024) { if (bytes % (1024) == 0) { SPrintf(out, "%d KB", bytes/1024); } else { SPrintf(out, "%d KB (%d bytes)", bytes/1024, bytes); } } else { SPrintf(out, "%d bytes", bytes); } return out; } string frequencyToPrintable(uint32_t freq) { local string out; SPrintf(out, "%d Hz", freq); return out; } string camelliaToPrintable(CamelliaVersion cam) { local string out; SPrintf(out, "%s (%d)", EnumToString(cam), cam); return out; } string connectorTypeToPrintable(ConnectorType type) { local string out; local string typename = EnumToString(type); Assert(typename != "", "Unknown connector type discovered"); SPrintf(out, "0x%08X - %s", type, EnumToString(type)); return out; } string connectorToPrintable(ConnectorInfo &con) { local string out; SPrintf(out, "[%d] busId: 0x%02X, pipe: %d, type: 0x%08X, flags: 0x%08X - %s", con.index, con.busId, con.pipe, con.type, con.flags.value, EnumToString(con.type)); return out; } string wideConnectorToPrintable(ConnectorInfoICL &con) { local string out; SPrintf(out, "[%d] busId: 0x%02X, pipe: %d, type: 0x%08X, flags: 0x%08X - %s", con.index, con.busId, con.pipe, con.type, con.flags.value, EnumToString(con.type)); return out; } string connectorToHex(ConnectorInfo &c) { local string out; SPrintf(out, "%02X%02X%02X%02X %08X %08X", c.index, c.busId, c.pipe, c.pad, ((c.type>>24)&0xff) | ((c.type<<8)&0xff0000) | ((c.type>>8)&0xff00) | ((c.type<<24)&0xff000000), ((c.flags.value>>24)&0xff) | ((c.flags.value<<8)&0xff0000) | ((c.flags.value>>8)&0xff00) | ((c.flags.value<<24)&0xff000000)); return out; } string wideConnectorToHex(ConnectorInfoICL &c) { local string out; SPrintf(out, "%08X %08X %08X %08X %08X %08X", ((c.index>>24)&0xff) | ((c.index<<8)&0xff0000) | ((c.index>>8)&0xff00) | ((c.index<<24)&0xff000000), ((c.busId>>24)&0xff) | ((c.busId<<8)&0xff0000) | ((c.busId>>8)&0xff00) | ((c.busId<<24)&0xff000000), ((c.pipe>>24)&0xff) | ((c.pipe<<8)&0xff0000) | ((c.pipe>>8)&0xff00) | ((c.pipe<<24)&0xff000000), ((c.pad>>24)&0xff) | ((c.pad<<8)&0xff0000) | ((c.pad>>8)&0xff00) | ((c.pad<<24)&0xff000000), ((c.type>>24)&0xff) | ((c.type<<8)&0xff0000) | ((c.type>>8)&0xff00) | ((c.type<<24)&0xff000000), ((c.flags.value>>24)&0xff) | ((c.flags.value<<8)&0xff0000) | ((c.flags.value>>8)&0xff00) | ((c.flags.value<<24)&0xff000000)); return out; } string framebufferFlagsToPrintable(FramebufferFlags &flags) { local string out; SPrintf(out, "%08X", flags.value); return out; } string connectorFlagsToPrintable(ConnectorFlags &flags) { local string out; SPrintf(out, "%08X", flags.value); return out; } string modelNameAddrToPrintable(uint64_t addr) { return ReadLine(addr - textSlide); } string framebufferSNBToPrintable(FramebufferSNB &fb) { local string out; SPrintf(out, "%s (%s, %d connectors%s)", fb.framebufferStr, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : ""); return out; } string framebufferIVBToPrintable(FramebufferIVB &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(fb.fFramebufferMemorySize)); return out; } string framebufferHSWToPrintable(FramebufferHSW &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenHaswell(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferBDWToPrintable(FramebufferBDW &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenHaswell(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferSKLToPrintable(FramebufferSKL &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenSkylake(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferCFLToPrintable(FramebufferCFL &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenSkylake(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferCNLToPrintable(FramebufferCNL &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenSkylake(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferICLHPToPrintable(FramebufferICLHP &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenSkylake(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } string framebufferICLLPToPrintable(FramebufferICLLP &fb) { local string out; SPrintf(out, "0x%08X (%s, %d connectors%s, %s?)", fb.framebufferId, fb.fMobile ? "mobile" : "desktop", fb.fPortCount, fb.fFramebufferMemorySize == 0 ? ", no fbmem" : "", bytesToPrintable(calculateStolenIceLake(fb.flags, fb.fStolenMemorySize, fb.fFBMemoryCount, fb.fFramebufferMemorySize))); return out; } /* Skip a little data to speedup the search. */ local int64_t pos = 0x20000, size = FileSize(); local uint32_t i = 0, j = 0; local uint32_t firstId = 0; /* This value is a total maximum of preallocated memory that can be used with all flag combinations. * I.e. if you want to change FBFramebufferCompression or FBFramebufferCommonMemory you may need * as much memory as fMaxStolen. With the flags untouched refer to fTotalStolen. */ local uint32_t fMaxStolen = 0; /* This value is a total maximum of preallocated memory that is necessary for current flag combinations. * This value must be <= preallocated memory in BIOS settings, Apple also calls it minStolenSize. * I.e. this is what the assertion panic checks during boot, it is compared against the BIOS value * obtained via PCI Config 16-bit read from GMCH Control #0 (0x50): ((val << 17) & 0xFE000000) - 0x1000 */ local uint32_t fTotalStolen = 0; /* This value is used for hardware cursor allocation, but is not checked. Bug? */ local uint32_t fTotalCursor = 0; /* The absolute maximum with all flag combinations including cursor and framebuffer memory. */ local uint32_t fMaxOverall = 0; local uint32_t magic = ReadUInt(0); if (magic != 0xFEEDFACF) { Printf("Invalid kext file!\n"); Exit(0); } local uint64_t textSlide = ReadUInt64(0x38); local uint32_t isLowProfile = FindFirst("ICLLP") > 0; while (pos < size) { /* Skip to platforms... */ firstId = ReadUInt(pos); if (firstId != FirstSandyBridgeId && firstId != FirstIvyBridgeId && firstId != FirstHaswellId && firstId != FirstBroadwellId && firstId != FirstSkylakeId && firstId != FirstKabyLakeId && firstId != FirstCoffeeLakeId && firstId != FirstCannonLakeId && firstId != FirstIceLakeId) { pos += sizeof(uint32_t); continue; } /* Read platforms from here... */ FSeek(pos); while (ReadUInt() != 0xFFFFFFFF) { if (firstId == FirstSandyBridgeId) { FramebufferSNB frames <optimize=false, read=framebufferSNBToPrintable>; frames[i].framebufferStr = frameIdFromIndex(frames[i].framebufferId, i); } else if (firstId == FirstIvyBridgeId) { FramebufferIVB frames <optimize=false, read=framebufferIVBToPrintable>; } else if (firstId == FirstHaswellId) { FramebufferHSW frames <optimize=false, read=framebufferHSWToPrintable>; } else if (firstId == FirstBroadwellId) { FramebufferBDW frames <optimize=false, read=framebufferBDWToPrintable>; /* Skylake and Kaby Lake share the struct as of 10.13.3 */ } else if (firstId == FirstSkylakeId || firstId == FirstKabyLakeId) { FramebufferSKL frames <optimize=false, read=framebufferSKLToPrintable>; } else if (firstId == FirstCoffeeLakeId) { FramebufferCFL frames <optimize=false, read=framebufferCFLToPrintable>; } else if (firstId == FirstCannonLakeId) { FramebufferCNL frames <optimize=false, read=framebufferCNLToPrintable>; } else if (firstId == FirstIceLakeId && isLowProfile) { FramebufferICLLP frames <optimize=false, read=framebufferICLLPToPrintable>; } else if (firstId == FirstIceLakeId) { FramebufferICLHP frames <optimize=false, read=framebufferICLHPToPrintable>; } Printf("ID: %s, STOLEN: %s, FBMEM: %s, VRAM: %s, Flags: 0x%08X\n", frameIdFromIndex(frames[i].framebufferId, i), bytesToPrintable(frames[i].fStolenMemorySize), bytesToPrintable(frames[i].fFramebufferMemorySize), bytesToPrintable(frames[i].fUnifiedMemorySize), firstId == FirstSandyBridgeId || firstId == FirstIvyBridgeId ? 0 : firstId == FirstIceLakeId ? frames[i].flags : frames[i].flags.value); if (firstId == FirstSandyBridgeId || firstId == FirstIvyBridgeId) { fMaxStolen = frames[i].fFramebufferMemorySize * frames[i].fFBMemoryCount; fTotalStolen = frames[i].fFramebufferMemorySize; /* the assert here does not multiply, why? */ } else if (firstId == FirstHaswellId || firstId == FirstBroadwellId) { fMaxStolen = frames[i].fStolenMemorySize * frames[i].fFBMemoryCount + frames[i].fFramebufferMemorySize + 0x100000; fTotalStolen = calculateStolenHaswell(frames[i].flags, frames[i].fStolenMemorySize, frames[i].fFBMemoryCount, frames[i].fFramebufferMemorySize); } else if (firstId == FirstIceLakeId) { fMaxStolen = frames[i].fStolenMemorySize * frames[i].fFBMemoryCount + frames[i].fFramebufferMemorySize + 0x100000; fTotalStolen = calculateStolenIceLake(frames[i].flags, frames[i].fStolenMemorySize, frames[i].fFBMemoryCount, frames[i].fFramebufferMemorySize); } else { fMaxStolen = frames[i].fStolenMemorySize * frames[i].fFBMemoryCount + frames[i].fFramebufferMemorySize + 0x100000; fTotalStolen = calculateStolenSkylake(frames[i].flags, frames[i].fStolenMemorySize, frames[i].fFBMemoryCount, frames[i].fFramebufferMemorySize); } fTotalCursor = frames[i].fPipeCount * 0x80000; fMaxOverall = fTotalCursor + fMaxStolen + frames[i].fPortCount * 0x1000; Printf("TOTAL STOLEN: %s%s, TOTAL CURSOR: %s, MAX STOLEN: %s, MAX OVERALL: %s\n", bytesToPrintable(fTotalStolen), firstId == FirstIceLakeId ? "?" : "", bytesToPrintable(fTotalCursor), bytesToPrintable(fMaxStolen), bytesToPrintable(fMaxOverall)); if (frames[i].fModelNameAddr != 0) Printf("Model name: %s\n", modelNameAddrToPrintable(frames[i].fModelNameAddr)); Printf("Camellia: %s, Freq: %s, FreqMax: %s\n", camelliaToPrintable(frames[i].camelliaVersion), frequencyToPrintable(frames[i].fBacklightFrequency), frequencyToPrintable(frames[i].fBacklightMax)); Printf("Mobile: %d, PipeCount: %d, PortCount: %d, FBMemoryCount: %d\n", frames[i].fMobile, frames[i].fPipeCount, frames[i].fPortCount, frames[i].fFBMemoryCount); if (firstId == FirstIceLakeId) { for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", wideConnectorToPrintable(frames[i].connectors[j])); for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", wideConnectorToHex(frames[i].connectors[j])); } else { for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", connectorToPrintable(frames[i].connectors[j])); for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", connectorToHex(frames[i].connectors[j])); } Printf("\n"); /* There is no -1 termination on Sandy */ if (firstId == FirstSandyBridgeId && i == 7) break; i++; } break; } /* Additionally read the externally defined default FB on Sandy */ if (firstId == FirstSandyBridgeId) { pos = 0x20000; while (pos < size) { firstId = ReadUInt(pos); if (firstId == DefSandyBridgeId) { FSeek(pos); FramebufferSNB frames <optimize=false, read=framebufferSNBToPrintable>; frames.framebufferStr = "Default"; Printf("Default SNB, DVMT: %s, FBMEM: %s, VRAM: %s, Flags: 0x00000000\n", bytesToPrintable(frames[i].fStolenMemorySize), bytesToPrintable(frames[i].fFramebufferMemorySize), bytesToPrintable(frames[i].fUnifiedMemorySize)); Printf("Camellia: %s, Freq: %s, FreqMax: %s\n", camelliaToPrintable(frames[i].camelliaVersion), frequencyToPrintable(frames[i].fBacklightFrequency), frequencyToPrintable(frames[i].fBacklightMax)); Printf("Mobile: %d, PipeCount: %d, PortCount: %d, FBMemoryCount: %d\n", frames[i].fMobile, frames[i].fPipeCount, frames[i].fPortCount, frames[i].fFBMemoryCount); for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", connectorToPrintable(frames[i].connectors[j])); for (j = 0; j < frames[i].fPortCount; j++) Printf("%s\n", connectorToHex(frames[i].connectors[j])); Printf("\n"); break; } else { pos += sizeof(uint32_t); } } Printf("Note, that without AAPL,snb-platform-id the following models will use predefined IDs:\n"); Printf("Mac-94245B3640C91C81 -> SNB0 (MacBookPro8,1)\n"); Printf("Mac-94245AF5819B141B -> SNB0\n"); Printf("Mac-94245A3940C91C80 -> SNB0 (MacBookPro8,2)\n"); Printf("Mac-942459F5819B171B -> SNB0 (MacBookPro8,3)\n"); Printf("Mac-8ED6AF5B48C039E1 -> SNB2 (Macmini5,1)\n"); Printf("Mac-7BA5B2794B2CDB12 -> SNB2 (Macmini5,3)\n"); Printf("Mac-4BC72D62AD45599E -> SNB3 (Macmini5,2) -> no ports\n"); Printf("Mac-742912EFDBEE19B3 -> SNB4 (MacBookAir4,2)\n"); Printf("Mac-C08A6BB70A942AC2 -> SNB4 (MacBookAir4,1)\n"); Printf("Mac-942B5BF58194151B -> SNB5 (iMac12,1) -> no ports\n"); Printf("Mac-942B5B3A40C91381 -> SNB5 -> no ports\n"); Printf("Mac-942B59F58194171B -> SNB5 (iMac12,2) -> no ports\n"); } else if (firstId == FirstSkylakeId) { Printf("Note, that without AAPL,ig-platform-id the following ID is assumed: 19120000\n"); } else if (firstId == FirstKabyLakeId) { Printf("Note, that without AAPL,ig-platform-id the following ID is assumed: 59160000\n"); } else if (firstId == FirstCoffeeLakeId) { Printf("Note, that without AAPL,ig-platform-id the following ID is assumed: 3EA50000\n"); } else if (firstId == FirstCannonLakeId) { Printf("Note, that without AAPL,ig-platform-id the following ID is assumed: 5A520000\n"); } else if (firstId == FirstIceLakeId) { Printf("Note, that without AAPL,ig-platform-id the following REAL ID is assumed: 8A520000\n"); Printf("Note, that without AAPL,ig-platform-id the following SIMULATOR ID is assumed: FF050000\n"); }