Help. My NVMe shows up as External…

Some people (see comments) are having issues with M.2 devices sitting behind a PCI bridge (IOName is pci-bridge) and then IONVMeFamily.kext fails to read the built-in property.

Update: Blog article updated for macOS Sierra DP4 !

The solution so far was to use a (tiny) SSDT (snippet) or add it to any other SSDT and to set the missing built-in property from a _DSM method, but we can also patch a few more bytes in the binary:

AppleNVMeController::InitializePCI()

test       rax, rax
je         0xa711
or         byte [ds:rbx+0x108], 0x10

Let’s just nop the first five bytes so that it looks like this:

nop
nop
nop
nop
nop
or         byte [ds:rbx+0x108], 0x10

In other words. You need Clover to search for the output of:

echo -n '4885c07407808b0801000010'|xxd -r -p|base64

And replace it with the output of:

echo -n '9090909090808b0801000010'|xxd -r -p|base64

Then you take the result and morph it into this:

    <dict>
        <key>Comment</key>
        <string>IONVMeFamily Pike R. Alpha Patch#External</string>
        <key>Disabled</key>
        <false/>
        <key>Name</key>
        <string>IONVMeFamily</string>
        <key>Find</key>
        <data>SIXAdAeAiwgBAAAQ</data>
        <key>Replace</key>
        <data>kJCQkJCAiwgBAAAQ</data>
    </dict>

Add the above lines to KextsToPatch in your Clover config.plist and that should fix it for you.

Edit: Confirmed working on a Gigabyte GA-Z87MX-D3H where a PCIe X4 card with a M.2 is installed in the PCIEX8 slot (Device _SB.PCI0.PEG1@1,1 in the DSDT).

Edit-2: I have since updated the tiny SSDT for this motherboard. Just rename PEG1 to the device that you are using. Like NPE7 for certain hardware 😉

Edit-3: ACPI code from said link (above) added.

        External(_SB.PCI0.PEG1, DeviceObj)

        /* PEG1 is used for my PCIe card with M.2, installed in slot 'PCIEX8' */

        Scope (\_SB.PCI0.PEG1)
        {
            /* Here we inject a new device (SSD0) for the PCIe card with M.2 */

            Device (SSD0)
            {
                Name (_ADR, Zero)  // _ADR: Address
                Name (NVME, One)
                Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
                {
                    If (LEqual (Arg2, Zero))
                    {
                        Return (Buffer (One)
                        {
                             0x03
                        })
                    }

                    If (LEqual (NVME, One))
                    {
                        Return (Package (0x04)
                        {
                            "use-msi", 
                            One, 
                            "nvme-LPSR-during-S3-S4", 
                            One
                        })
                    }
                    Else
                    {
                        Return (Package (0x06)
                        {
                            "use-msi", 
                            One, 
                            "sata-express-power-off", 
                            One, 
                            "ssd-off-in-S4", 
                            One
                        })
                    }
                }

                Device (PRT0)
                {
                    Name (_ADR, 0xFFFF)  // _ADR: Address
                    Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
                    {
                        If (LEqual (Arg2, Zero))
                        {
                            Return (Buffer (One)
                            {
                                 0x03
                            })
                        }

                        Return (Package (0x02)
                        {
                            "io-device-location", 
                            Buffer (0x04)
                            {
                                "SSD"
                            }
                        })
                    }
                }
            }
        }

29 thoughts on “Help. My NVMe shows up as External…

  1. Pingback: IONVMeFamily.kext changes in Sierra DP4 (build 16A270f) – Pike's Universum

  2. hi Pikeralpha, sorry it didn’t work for me (adding the lines above) KextsToPatch in my Clover config.plist

    this is what my iojones output looks like for my NVME disk, thanks if you can help, and thank you for all the hard work, i’ve been using numerous patches of yours and slowly learning this thing

    http://imgur.com/a/3yEhU

  3. success! thanks for the work Pikeralpha, i’m testing Sierra PB7 at the moment and your NMVE IONVMeFamily.kext bin patch data and external drive patch work a treat.

    Just to let you know yes i was using El Capitan before 🙂

    Many thanks

  4. Hi Pike this appear to be working for El Capitan, only one byte change from Sierra
    // El Capitan external icon fix
    UInt8 Find[] = {0x48, 0x85, 0xC0, 0x74, 0x07, 0x80, 0x8B, 0x00, 0x01, 0x00, 0x00, 0x10};
    UInt8 Replace[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x80, 0x8B, 0x00, 0x01, 0x00, 0x00, 0x10};

    cheers

  5. Pike, I was able to successfully apply this patch, thank you.

    I’d also like to patch my AHCI kext so that my other PCIe SSDs show up as internal.

    The trouble is– I don’t really understand how to replicate the process you went through to figure this out. I’m really trying to learn how to edit kexts.

    I understand I can open the binary up with Hexfriend and other Hex editors but I don’t know what I should/can replace. I’m also not quite sure how to track down the kext responsible for this. I’m relatively its either in the IOAHCIFamily.kext or AppleAHCIPort.kext but I’m just guessing.

    Do you think you could help me walk through this? Teach a man to fish…

    Thank you so much!

    • Download/install Hopper v4 and “Menu File/Read Executable To Disassemble…” the binary of said kext. Switch to “Strings” and go hunting for text like: internal, built-in and ESB2 AHCI. That should help.

      Note: The demo version of Hopper won’t let you save your changes. Use the HEX editor of your choice to change the locations that you need to change.

      • Thanks Pike,

        I downloaded used the Hopper app to find ESB2 within AppleAHCIPort binary. But now I’m not sure what to do.

        Could you help me understand why you had me search for ESB2?

        Thank you for your help!

        Nick

      • Click on the green link at the right, which will show you the actual disassembled code.

        And in the past, motherboards with the ICH9/10 had some issues (Google it, like I just did) where people injected a device-id of the ESB2 to get rid of the yellow drive icon(s). You should also check the hot-plug setting(s) in your BIOS. Disabling may also help.

        Note that I have no time to look into this, so you are on your own here. All free time that I have left right now is used for Kaby Lake research – macOS Sierra is booting up just fine, but with some issues that I need to fix.

      • Hey Pike,

        I’ve been trying to understand editing the DSDT and inject a device but I can’t really make the connection. Can you link me to a basic article that would help me understand more about editing a DSDT file?

        I’m trying to figure out how to inject a device, where the code goes, and how to know what the code block should look like.

        The more basic, the better!

      • Adding devices can be done with help of a SSDT.aml (see also Tiny-SSDT-example-3) but SSD devices are usually there already. Open IORegistryExplorer and look for your NVMe SSD device. You can probably find it under \_SB.PCI0.RPnn or \_SB/PCI.PEGn. So tell me. Did you find it and where is it?

      • Thanks a lot for your response Pike, I know it’s time consuming to help people such as myself.

        The Revoboot example was helpful.

        I’m looking for my NVMe drives, which I have 3, and I cannot seem to find them. According to IORegistryExplorer they are under BR2A/HDAU and BR3A/H000 but this is all I have:

        When I look for the \_SB.PCI0.RPnn devices I find these, but no indication to what they are.

        Here is my extracted SSDT, but only CPU-related items appear there. I did the searching for the devices in my DSDT.aml.
        https://www.dropbox.com/s/inwd4hf5elrpo9t/ssdt.dsl?dl=0

        Any advice on what to I do now?

        Again, I appreciate your help and time.

        Best,
        Nick

      • Hi Nick,

        No. It’s not Device (HDAU). That is usually dGPU audio related. I can’t do much with screenshots. I need to see your dump of IORegistryExplorer in order to help you.

      • Ok that is odd. There is indeed a bridge HDAU. Did you give it this name?

        Anyway. I see devices where you said they are. For the first one you want:

        Scope (\_SB.PCI0.BR2A.IOPP.HDAU.IOPP)
        {
            Device (SSD0)
            {
                Name (_ADR, 0x08)
            }
        }
        
        Scope (\_SB.PCI0.BR2A.IOPP.HDAU.IOPP.SSD0.IOPP)
        {
            Device (SSD)
            {
                Name (_ADR, Zero)
            }
        }
        

        If that works, then you can continue to add more code snippets. One by one:

        Scope (\_SB.PCI0.BR3A.IOPP.H000.IOPP)
        {
            Device (SSD1)
            {
                Name (_ADR, 0x09)
            }
            Device (SSD2)
            {
                Name (_ADR, 0x10)
            }
        }
        
        Scope (\_SB.PCI0.BR3A.IOPP.H000.IOPP.SSD1.IOPP)
        {
            Device (SSD)
            {
                Name (_ADR, Zero)
            }
        }
        
        Scope (\_SB.PCI0.BR3A.IOPP.H000.IOPP.SSD2.IOPP)
        {
            Device (SSD)
            {
                Name (_ADR, Zero)
            }
        }
        

        Do this step by step. And if one name showed up, but is gone again after adding the next code snippet, then something is not right. Check the paths. Remember. I do this at work. Don’t have a lot of time. Besides that. You need to learn and do stuff on your own 😉

        Ok. So when all names are there, then you can add a method _DSM under the Device (SSD) with properties that you may want to add.

        Good luck!

      • Hey Pike,

        I had a change to try this tonight and I’m having an issue. When I tried to add to the bottom of my SSDT then inside the Scope (_SB.PCI0.BR2A) of my DSDT I am getting the following error:

        Do I just need to keep nesting more of these scope items until I get back up to Scope (_SB.PCI0.BR2A)? (If so, what happens with _ADR?)

        To answer your last question, no I did not give it the name HDAU, in fact I cannot even find HDAU in my DSDT or SSDT files. So strange. My board is an Asus X99-E WS.

        Let me know if I can donate for your help. I accept donations on my blog when I help people with Hackintosh so it makes sense to pay it forward.

        Nick

      • Don’t forget to add the External () declarations. They are missing in my examples – took a shortcut here. Sorry.

        HDAU can be found in the ioreg dump that you link to here in a previous post.

        Thank you kindly for the offer, but I do not accept donations at this time.

      • Hey Pike,

        I managed to add the code snippet you gave me to my SSDT and compile with no errors. Thanks for getting me that far.

        Now the question becomes- How do I know if it “worked”? And how might I force my newly defined SSDs to be displayed as an internal drives?

        I’ve got 3x 950 Pros in Raid 0 and two Samsung XP941 (AHCI) drives for setting up new installations/backups/testing. All are shown as external drives with the orange icon. Your kext patch works for the NVMe drives but it would be really enlightening to know how to do it at the DSDT/SSDT level.

        Thanks as always for your time. It is scarce and a real treat to have your help.
        Nick

      • Hi Nick,

        Thanks. As for the external (orange) drive icons. Have you tried to add the Name (NVME, One) and _DSM method from my code snippet example? Are you saying that it doesn’t work for your setup?

  6. Hi. Pike.
    This patch seems to change under 10.12.4 16E144f.
    The new one:
    48 85 C0 74 07 80 8B 18 01 00 00 10 ==> 90 90 90 90 90 80 8B 18 01 00 00 10
    Previous the $8 was 0x08 and now it’s 0x18.

  7. After adding these ACPI properties, with the addition of “deep-idle” property:

    If (LEqual (NVME, One))
    {
    Return (Package (0x06)
    {
    “deep-idle”,
    One,
    “use-msi”,
    One,
    “nvme-LPSR-during-S3-S4”,
    One
    })
    }

    There’s something very promising in my log! But I expected to see a lot of these messages, for example a powerstate change when writing a big file. They seem to be set, instead, only at boot, sleep, resume from sleep. But it’s a start… isn’t ‘it?

    (IONVMeFamily) virtual IOReturn IONVMeController::setPowerState(unsigned long, IOService *)::214:
    (IONVMeFamily) virtual IOReturn IONVMeController::setPowerState(unsigned long, IOService *)::147:
    (IONVMeFamily) virtual IOReturn IONVMeController::setPowerState(unsigned long, IOService *)::155:

Leave a comment