Apple NVMe SMART Monitor Under Control…

Apple isn’t sharing any information about their SMART API’s so I had to dig a little and this is the first result (spoiler alert) from my hack:


-----------------------------------------
Smart Log for NVME device...............: disk0
NamespaceID.............................: 1
Critical Warning........................: 0
Temperature.............................: 37 °Celsius
Available Spare.........................: 100%
Available Spare Threshold...............: 10%
Percentage Used.........................: 1%
Data Units Read.........................: 4,292,043,776,000 [4.29 TB]
Data Units Written......................: 2,145,884,672,000 [2.14 TB]
Host Read Commands......................: 151780827
Host Write Commands.....................: 50512740
Controller Busy Time....................: 248 minutes
Power Cycles............................: 1541
Power On Hours..........................: 1156 hours
Unsafe Shutdowns........................: 784
Media and Data Integrity Errors.........: 0
Number of Error Information Log Entries.: 34

Here is an older one from my MacBook Pro:

-----------------------------------------
Smart Log for NVME device...............: disk0
NamespaceID.............................: 1
Critical Warning........................: 0
Temperature.............................: 22 °Celsius
Available Spare.........................: 100%
Available Spare Threshold...............: 10%
Percentage Used.........................: 0%
Data Units Read.........................: 7086678
Data Units Written......................: 4943651
Host Read Commands......................: 11389069
Host Write Commands.....................: 7246825
Controller Busy Time....................: 44 minutes
Power Cycles............................: 431
Power On Hours..........................: 9 hours
Unsafe Shutdowns........................: 15
Media and Data Integrity Errors.........: 0
Number of Error Information Log Entries.: 0

The temperature on my MacBook Pro is lower. Only 22 °Celsius. I was also unpleasantly surprised by the fifteen ‘Unsafe Shutdowns’ on it. This has to be a driver issue. Never had a single freeze, lockdown or sudden reboot.

The high number of ‘Unsafe Shutdowns’ on the hack is easily explainable. As you know, I do a lot of testing and then things can go wrong. And they do go wrong with a couple of beta kernel drivers.

More to come…

Advertisements

Supported Mac models for Night Shift in Sierra 10.12.4+

Night Shift was introduced in macOS Sierra 10.12.4 (Build 16E144f and Public Beta-1) and is controlled by the CoreBrightness.framework and you’ll need at least one of the following – or later – Mac models:

MacBookPro9,x
iMac13,x
Macmini6,x
MacBookAir5,x
MacPro6,x
MacBook8,x

Apple did not release any information about this. Not just yet, but I know this because I located the checks for it in said framework, and there it checks for matching Mac model names:

MacBookPro
iMac
Macmini
MacBookAir
MacPro
MacBook

Night Shift is however not supported – by Apple – on older Mac models. No. There are checks for minimum requirements, which I looked up with help of:

nm /S*/L*/PrivateFrameworks/CoreBrightness.framework/CoreBrightness|grep _ModelMinVersion

000000000001d490 S _ModelMinVersion

Ok. Now we know the offset. Time to dump the data with help of:

xxd -s 0x1D490 -l 24 /S*/L*/PrivateFrameworks/CoreBrightness.framework/CoreBrightness

0001d490: 0900 0000 0d00 0000 0600 0000 0500 0000
0001d4a0: 0600 0000 0800 0000

MacBookPro9,x
iMac13,x
Macmini6,x
MacBookAir5,x
MacPro6,x
MacBook8,x

I opened the CoreBrightness binary in a hex editor (app) and change the coloured byte that matches with the used hardware. After that I saved the file and copied it to the original location.

The next step is to re-sign the patched framework binary with:

sudo codesign -f -s - /S*/L*/PrivateFrameworks/CoreBrightness.framework/Versions/Current/CoreBrightness

Well. Now you know how I did it, and in case you happen to own a Mac model that isn’t supported, yet, then you could try to patch the matching value in CoreBrightness.framework as some readers here confirmed that this is working for them with older/unsupported hardware.

Note: The colours that I used should help you to find the byte that you need to change.

Anyway. This my friends is how it is done. Have fun now.

Edit: The order of the MacBook Pro and iMac was wrong – see comments. Fixed thanks to the heads up from Thomas and Nicolinux.

Note: You may only use this patch in your script/software/app if the source code is available, preferable on Github, you are not asking for donations, and clearly state that this is my work. Thank you.

Apple IGPU saved-config data

I own two new Mac Book Pro’s. One IGPU only (MacBookPro13,1) and one with a Radeon Pro 460 with 4GB (MacBookPro13,3). Both of them use device-properties to inject saved-config. The injected data is related to the display hardware and I like to find out what that data is and where that it is used. Let’s start with a grep:

grep -r saved-config /System/Library/Extensions

Here is the output:

AMDFramebuffer.kext
AMDSupport.kext
AppleIntelBDWGraphicsFramebuffer.kext
AppleIntelFramebufferAzul.kext
AppleIntelFramebufferCapri.kext
AppleIntelHDGraphicsFB.kext
AppleIntelSKLGraphicsFramebuffer.kext
AppleIntelSNBGraphicsFB.kext
NVDAResman.kext
NVDAResmanTesla.kext
NVDAResmanWeb.kext

This basically tells us the names of the kexts that are using the data, but now we have to find out what the data is. Here is the data that gets injected on the MacBookPro13,3:

47 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 06 00 1b 19 00 6c 05
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 06 10 30 a0 02
03 40 00 00 00 00 00 00 00 00 02 c0 eb 9a 13 40 0b 08 07 50 00 00 00 34 00 00 00
08 00 20 00 26 00 08 00 20 0d 34 08 69 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00

And here the data that is injected on the MacBookPro13,1

47 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 02 00 26 19 00 6c 05
69 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 06 10 34 a0 02
03 40 00 00 00 00 00 00 00 00 02 90 6c 8a 0f 00 0a 40 06 50 00 00 00 2e 00 00 00
08 00 20 00 20 00 08 00 40 0b 08 07 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00

I could not find anything, not a single Apple document nor source code/header file that explains it, but I may have missed it. In which case I would love to hear from you.

Ok. So assuming that there is no documentation, we have to dig into other resources to get an idea what it may be. And this is what I figured out so far:

47 00 00 00 (unknown)

00 00 00 00 (_reservedA[10])
00 00 00 00
00 00 00 00

00 00 03 00 (version?)

06 00 1b 19 (AAPL,ig-platform-id)

00 (unknown)

6c 05 (BCL frequency/maximum?)

00 00 (BCL frequency/minimum)

00 00 (unknown)

00 00 00 00 (_reservedB[10])
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00

01 01 01 01 (standard timing related info?)

00 (unknown)

06 10 (DisplayVendor)

30 a0 (DisplayProductID)

02 03 40 00 00 00 00 00 00 00 00 02 (unknown)

c0 eb 9a 13 (IOFBCurrentPixelClock)

40 0b (horizontalActive = 2880 pixels)

08 07 (verticalActive = 1800 pixels)

50 00 (horizontalBlanking in pixels)

00 (horizontalBorderLeft in pixels)

00 (horizontalBorderRight in pixels)

34 00 (verticalBlanking in pixels)

00 (verticalBorderTop in pixels)

00 (verticalBorderBottom in pixels)

08 00 (horizontalSyncOffset in pixels)

20 00 (horizontalSyncPulseWidth/Sync Width)

26 00 (verticalSyncOffset in pixels)

08 00 (verticalSyncPulseWidth/Sync Width)

20 0d (horizontalScaled = 3360)

34 08 (verticalScaled = 2100)

69 00 (bytes per row == ( (horizontalActive * depth) >> 3) )

00 00 00 00 (_reservedC[25])
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00

Mostly basic stuff. Things that you could have come up yourself, but since I like to document things, and let other people confirm my findings.

Edit: I changed the border info. It’s now broken up into two horizontal and vertical border settings. I also figured out the unknown value at the bottom (row bytes).

The red unknown values are my next targets and I think that one of them is used for screen rotation. This is something I will test later today on my MacBook Pro.

Ok. Let me add the EDID data that gets injected:

00 ff ff ff ff ff ff 00 06 10 30 a0 00 00 00 00 26 19 01 04 b5 21 15 78 02 0f 55
ae 52 43 b0 26 0d 4f 54 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
7c 80 40 50 b0 08 34 70 08 20 68 08 4b cf 10 00 00 1a 00 00 00 10 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 fc 00 43 6f 6c 6f 72 20 4c 43 44 0a 20 20 20
00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe

And here the EDID data from the MacBookPro13,1

00 ff ff ff ff ff ff 00 06 10 34 a0 00 00 00 00 25 19 01 04 b5 1d 12 78 02 0f 41
ae 52 43 b0 26 0e 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
d9 65 00 50 a0 40 2e 60 08 20 08 08 1e b3 10 00 00 1a 7c 80 40 50 b0 08 34 70 08
20 68 08 1e b3 10 00 00 1a 00 00 00 fc 00 43 6f 6c 6f 72 20 4c 43 44 0a 20 20 20
00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3e

I also used SwitchResX to dump the EDID and one particular part of that output is this:

EDID Detailed mode

Clock 328.920 MHz, 331 mm x 207 mm
2880 2888 2920 2960 hborder 0
1800 1838 1846 1852 vborder 0
+hsync -vsync

I also used DarwinDumper and this is what I got:

Mode = 2880 x 1800 @ 60.001Hz
Pixel Clock............. 328.92 MHz Non-Interlaced

Horizontal Vertical
Active.................. 2880 pixels 1800 lines
Front Porch............. 8 pixels 38 lines
Sync Width.............. 32 pixels 8 lines
Back Porch.............. 40 pixels 6 lines
Blanking................ 80 pixels 52 lines
Total................... 2960 pixels 1852 lines
Scan Rate............... 111.122 kHz 60.001 Hz

Image Size.............. 331 mm 207 mm
Border.................. 0 pixels 0 lines

Sync: Digital separate with
* Negative vertical polarity
* Positive horizontal polarity

The above data is the technical description of the 15-inch display panel. And I used it, along with the saved-config data, to get this:

First column

2880 = horizontalActive
1800 = verticalActive

Second column

2880 = 2880 (horizontalActive) + 8 (horizontalSyncOffset)
1838 = 1800 (verticalActive) + 0x26/38 (verticalSyncOffset)

Third column

2920 = 2880 (horizontalActive) + 8 (horizontalSyncOffset) + 0x20/32 (horizontalSyncPulseWidth)
1846 = 1800 (verticalActive) + 0x26/38 (verticalSyncOffset) + 8 (verticalSyncPulseWidth)

Fourth column

2960 = 2880 (horizontalActive) + 0x50/80 (horizontalBlanking)
1852 = 1800 (verticalActive) + 0x34/52 (verticalBlanking)

Most of it can be extracted from IODisplayEDID, but I like to see it confirmed by others first. There is also unknown data. I have no idea, yet, what it may be. For example: 69 00 is 5a 00 on my MacBookPro13,1 and I have no idea what it is or how to get this value for my external monitor.

Injecting the wrong data is not what we want. I tried that and it failed to boot. The monitor of my hack went nuts, so the data obviously did something.

In short. We need a script or app that does most, if not all, of the work for us. We can use struct IODetailedTimingInformationV2 from IOGraphicsTypes.h to get (most of the) data. After that we can try to figure out what it does or if it helps us. Now the question is; who here is interested in this, and who can write that script and/or app?

Note: Some people may say that we don’t need it. Sure. We have been booting OS X for many years without this data. True. But now answer this question: Why does Apple inject the device-properties, when they don’t need it?

Does Apple load microcode for the IGPU?

Someone asked me if I knew if Apple loads Graphics micro code (Guc) for the IGPU and I can confirm that. Yes it does. Take a look at the following log data from my Apple MacBookPro13,3:

kernel: (AppleIntelSKLGraphics) [IGPU] Will fallback to host-side scheduling if graphics firmware fails to load
kernel: (AppleIntelSKLGraphics) [IGPU] Chose to use graphics firmware based on platform
kernel: (AppleIntelSKLGraphics) [IGPU] Graphics accelerator is using scheduler interface revision 3: Apple Firmware
kernel: (AppleIntelSKLGraphics) [IGPU] Scheduler: Multiple channel indexes per command streamer
kernel: (AppleIntelSKLGraphics) [IGPU] Scheduler: Process CSB using HWS.
kernel: (AppleIntelSKLGraphics) [IGPU] Scheduler: PM notify enabled
kernel: (AppleIntelSKLGraphics) [IGPU] Graphics Address: PPGTT, Separate Address Space
kernel: (AppleIntelSKLGraphics) [IGPU] MultiForceWake Enabled: Using 3D Driver
kernel: (AppleIntelSKLGraphics) [IGPU] Begin GuC load process
kernel: (AppleIntelSKLGraphics) [IGPU] Begin GuC load process
kernel: (AppleIntelSKLGraphics) [IGPU] ForceWake Multithread = 0x20002
kernel: (AppleIntelSKLGraphics) [IGPU] ForceWake Multithread = 0x20002
kernel: (AppleIntelSKLGraphics) [IGPU] CONFIG0 (0xD00) = 0x80000000
kernel: (AppleIntelSKLGraphics) [IGPU] CONFIG0 (0xD00) = 0x80000000
kernel: (AppleIntelSKLGraphics) [IGPU] GT_THREAD_STATUS = 0x400b0000
kernel: (AppleIntelSKLGraphics) [IGPU] GT_THREAD_STATUS = 0x400b0000
kernel: (AppleIntelSKLGraphics) [IGPU] Doing retry #0
kernel: (AppleIntelSKLGraphics) [IGPU] Doing retry #0

Edit: We can disable the firmware load with help of boot argument -disablegfxfirmware which may come in handy in due time. Another boot argument is -disablegfxpreemption.

Debugging sleep issues…

A lot of people are still facing sleep/wake related issues and I like to figure out why so please check:

IOService:/AppleACPIPlatformExpert/IOPMrootDomain/PMStatusCode

1.) Is that number a zero or some other value?
2.) Do you have a property with the name: IOPMDeepIdleSupported?
3.) Do you have a property with the name: IOPMSystemSleepType?

If the answer for the first question is zero, then I would like to know if you are using a dGPU or IGPU only.

The second question can be solved by adding the following code to your ACPI tables:

Scope (\_SB)
{
    Method (LPS0, 0, NotSerialized)
    {
        Store ("Method \\_SB._LPS0 Called", Debug)
        Return (One)
    }
}

Scope (\_GPE)
{
    Method (LXEN, 0, NotSerialized)
    {
        Store ("Method \\_GPE.LXEN Called", Debug)
        Return (One)
    }
}

If the answer for the last question is yes, then what value is it, and what SMBIOS are you using? Please note that this specific property is not part of Yosemite. The value represents the lowest possible sleep state and is checked by the following kexts:

AppleACPIPlatform.kext
AppleIntelBDWGraphicsFramebuffer.kext
AppleIntelFramebufferAzul.kext
AppleIntelSKLGraphicsFramebuffer.kext
AppleSDXC.kext
AppleStorageDrivers.kext
IO80211Family.kext
IOBluetoothFamily.kext
IONVMeFamily.kext
IOUSBAttachedSCSI.kext
IOUSBMassStorageDriver.kext

That should be enough reasons for you to want that property.

I also added the following code to my ACPI tables:

Scope (\)
{
   Name (SLTP, Zero)

   Method (_TTS, 1, NotSerialized)
   {
       Store ("Method \\__TTS Called", Debug)
       Store (Arg0, SLTP)
   }
}

This, with additional checks, is used by Apple to skip parts for the NVMe SSD (RP01/IOPP/SSD0@0), AirPort (RP09/IOPP/ARP@0) and camera (RP10@1D,1/IOPP/CMRA) devices

NVRAM

There are two interesting NVRAM properties:

#define kIOSleepWakeDebugKey        "Persistent-memory-note"
#define kIOEFIBootRomFailureKey     "wake-failure"

That has to be it for now. Maybe later more…

Edit:

Ok. Jaybee asked (see comments) how he should validate the values. That is a good question. Let’s start with PMStatusCode. This should be 0x0 (success).

IOPMDeepIdleSupported. This should be there with a value of true.

IOPMSystemSleepType is the lowest possible sleep state and this is set to 7 on my MacBook Pro. This will also issue a sleep request for the iGPU.

Some people said that this property wasn’t there on their setup. For some not until after a sleep/wake cycle, and then it was set to 2.

I have yet to figure out how important this value is and if that can cause any trouble.

AppleIntelSKLGraphicsFramebuffer.kext

Here is the first data from the AppleIntelSKLGraphicsFramebuffer.kext binary that I like to share with you:

06 00 1B 19 00 00 00 00 91 09 08 00 00 00 00 00
01 01 01 01 00 00 60 02 00 00 00 00 00 00 00 60
6C 05 00 00 6C 05 00 00 00 00 00 00 00 00 00 00
00 00 08 00 02 00 00 00 98 04 00 00 FF 00 00 00
01 00 00 00 20 00 00 00 FF 00 00 00 01 00 00 00
20 00 00 00 FF 00 00 00 01 00 00 00 20 00 00 00
02 13 13 00 00 00 06 00 03 00 00 00 04 00 00 00
80 DF 17 10 00 00 00 00 78 05 00 00 D2 05 00 00
40 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10 23 1B 00 00 00 00 00 60 24 1B 00 00 00 00 00
60 24 1B 00 00 00 00 00 01 00 00 00 08 00 00 00
00 00 00 00 00 00 00 00

The above example will activate/support only one display, and some of the data is well known by now so I am going to skip stuff like the black value, which is (still) the platformID.

Unused/disabled frame buffer data (see orange values) have also changed.

New are the red values, all represent a different kinds of version information.

New is the blue value, representing the number of Slices (Slice Count).

New is the green value, representing the number of Execution Unit (EU Count).

The purple data is used for the TCON configuration and this is what I found in the log file of my MacBookPro13,3:

kernel: (AppleIntelSKLGraphicsFramebuffer) IG: TCON:
kernel: (AppleIntelSKLGraphicsFramebuffer) Aux not ready at HW
kernel: (AppleIntelSKLGraphicsFramebuffer) IG: TCON:
kernel: (AppleIntelSKLGraphicsFramebuffer) BAN_DPCD_0x0_EXPECTED failed, got deadbeef

See also:

AppleIntelFramebufferAzul.kext (Part I)
AppleIntelFramebufferAzul.kext (Part II)
AppleIntelFramebufferAzul.kext (Part III)