Contribute
Register

[Guide] HackrNVMeFamily co-existence with IONVMeFamily using class-code spoof

Status
Not open for further replies.
Hi @RehabMan. Thank you so much for your hard work on this. Could you possibly help me figure out this path?

ssd.jpg
 
Hi @RehabMan. Thank you so much for your hard work on this. Could you possibly help me figure out this path?

View attachment 226625

Guessing a bit here... But I think your device is without an ACPI identity, but its parent does have an identity (_SB.PCI0.P0P4)

So... You only need to add the leaf node...

Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.P0P4, DeviceObj)
    Device(_SB.PCI0.P0P4.SSD0) { Name(_ADR, 0) } // adding SSD0 identity under _SB.PCI0.P0P4
    Method(_SB.PCI0.P0P4.SSD0._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF
 
Guessing a bit here... But I think your device is without an ACPI identity, but its parent does have an identity (_SB.PCI0.P0P4)

So... You only need to add the leaf node...

Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.P0P4, DeviceObj)
    Device(_SB.PCI0.P0P4.SSD0) { Name(_ADR, 0) } // adding SSD0 identity under _SB.PCI0.P0P4
    Method(_SB.PCI0.P0P4.SSD0._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF

Thanks, this worked for me. I am able to see the drive in 10.12.2 and was able to install MacOS on it but I can't boot from it. Neither the bios nor clover recognize the drive. I am using an old Asus P35 motherboard. Is there anything I can do to get it to boot?
 
Neither the bios nor clover recognize the drive. I am using an old Asus P35 motherboard. Is there anything I can do to get it to boot?

Probably not. Need a modern UEFI BIOS with NVMe support.
 
Merry Christmas RehabMan and tonymac.
 

Attachments

  • Merry Christmas.jpg
    24.5 MB · Views: 648
Last edited by a moderator:
Overview

The purpose of this guide is to explain how to use the class-code spoof technique to keep un-patched IONVMeFamily.kext (incompatible with most PC NVMe SSDs) from loading such that HackrNVMeFamily can be used along side it in EFI/Clover/kexts or installed to the system volume (/Library/Extensions, /System/Library/Extensions).

I first published the technique on insanelymac: http://www.insanelymac.com/forum/to...er-macos-sierra-is-ready/page-29#entry2322636

You should be familiar with the patch_nvme.sh script as discussed in the patch-nvme README on github: https://github.com/RehabMan/patch-nvme

Although there are many ways to patch IONVMeFamily, only the class-code spoof and HackrNVMeFamily is to be discussed here. It is my opinion that it is the best way. Keeping this post focused only on this single technique, used from installation through post-installation, is the least confusing way to approach the topic.

There are two different ways to implement the class-code spoof:
- SSDT with _DSM method to inject the modified class-code
OR
- using config.plist/Devices/Arbitrary to inject the modified class-code

Because using config.plist/Devices/Arbitrary precludes use of some commonly used Clover features (config.plist/Graphics/Inject), this post will discuss only the SSDT method.

Assumptions:
- installation of Windows on the target
- running install of macOS/OS X (same version as you plan for the target) on existing hack or Mac
- basic config.plist editing skills
- basic MaciASL usage
- basic Clover knowledge
- basic knowledge of installing/injecting kexts


Determining the ACPI path of your NVMe device(s)

In order to create an SSDT to inject class-code, you must know the ACPI path that describes where your SSD is located in ACPI namespace. You can use Windows Device Manager, or advanced users can determine it from ioreg. Both methods are described at the insanelymac link provided in the patch-nvme README.

Because this guide is intended to be used prior to installation, it will use Windows Device Manager. You will find your NVMe device in Windows Device Manager under "Storage Controllers" -> "Standard NVM Express Controller". Right click and choose Properties. Then click on the "Details" tab. Then find "BIOS device name" within the "Property" dropdown. Select it. Your NVMe SSD ACPI path will be displayed in the "Value" box.

View attachment 226134

If you have more than one NVMe SSD, you must find the ACPI path for each one.

Note: It is also possible that your SSD has no ACPI identity. I don't have such a computer at the moment (and the situation is probably rare), but in that case you may be able to determine only the ACPI identity of the parent (in the case of my NUC, the parent is _SB.PCI0.RP13), and slightly different SSDT would have to be created.


Creating SSDT-NVMe-Pcc.aml

Below you'll find a template you can use for your own SSDT that injects class-code. This is the actual SSDT that I use on my NUC6i7KYK with a Samsung 950 Pro NVMe SSD:
Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.RP13.PXSX, DeviceObj)
    Method(_SB.PCI0.RP13.PXSX._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF

The path shown above _SB.PCI0.RP13.PXSX is the path that my NUC6i7KYK uses. You will notice the same path was shown in the image from Windows Device Manager. You will need to replace both instances of it in the above SSDT to match the path for your own NVMe SSD.

If your SSD had no ACPI identity (eg. no ACPI identity for the M.2 port/device), you would need to create one. For example, if the OEM had left out the PXSX identity, it would have been required that I add one:
Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.RP13, DeviceObj)
    // Add PXSX device under RP13
    Device(_SB.PCI0.RP13.PXSX) { Name(_ADR, 0) }
    /// Now we can inject the method at RP13.PXSX
    Method(_SB.PCI0.RP13.PXSX._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF

I don't know what is displayed in Windows Device Manager in that case, although it is predictable what ioreg would look like. Of course, the idea here is to create the SSD before installing macOS, so let me know if you have a situation with no ACPI identity for the SSD.

And if you have multiple NVMe SSDs, you must create a _DSM method for each. For example, my NUC also has a M.2 port at RP09 for an SSD. Currently, I have an SM951/AHCI installed there, so it is not NVMe. But if it was an NVMe drive, my SSDT would have to modified to include a _DSM method for it as well:

Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.RP09.PXSX, DeviceObj)
    Method(_SB.PCI0.RP09.PXSX._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
    External(_SB.PCI0.RP13.PXSX, DeviceObj)
    Method(_SB.PCI0.RP13.PXSX._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF

In order to use this SSDT, you must compile it as AML. You can use my version of MaciASL, which is linked from my ACPI patching guide:
https://www.tonymacx86.com/threads/guide-patching-laptop-dsdt-ssdts.152573/

Use File.Save As, "SSDT-NVMe-Pcc.aml", Format: ACPI Machine Language Binary. Save to a location you can find, such as your desktop.

Now you can copy the SSDT-NVMe-Pcc.aml file such that Clover can load it. If you're preparing your USB, you'll place it on the EFI for USB, otherwise it will be on the EFI for your boot drive. In any case, it goes to EFI/Clover/ACPI/patched/SSDT-NVMe-Pcc.aml.

Note: If you're using config.plist/ACPI/SortedOrder (to set SSDT load order for patched OEM SSDTs), you must be certain SSDT-NVMe-Pcc.aml is in the SortedOrder list. When SortedOrder is specified, SSDTs in ACPI/patched that are not in SortedOrder are ignored by Clover. For most desktop scenarios and laptop scenarios where Clover ACPI hotpatching is being used, SortedOrder will not be specified and copying the file to ACPI/patched is sufficient to cause it be loaded.


Existing _DSM methods

It is possible your OEM already defined a _DSM method at the ACPI path that defines your NVMe SSD in ACPI namespace. ACPI does not allow duplicate symbols at the same path, so if you have an existing _DSM, the _DSM we are trying to add via SSDT-NVMe-Pcc.aml will be ignored.

Although you can patch DSDT (or any OEM SSDT that may have the offending _DSM), I like to use a Clover patch to rename all _DSM methods to XDSM. Clover ACPI patches are specified at config.plist/ACPI/DSDT/Patches.

An entry for _DSM->XDSM would be:
Comment: Change all _DSM to XDSM
Find: <5f44534d>
Replace: <5844534d>

As it appears in Xcode:
View attachment 226136

Renaming all _DSM to XDSM insures no existing _DSM at the NVMe SSD path. The _DSM injection via SSDT-NVMe-Pcc.aml will not work if there is an existing _DSM at that path.

You can find the _DSM to XDSM patch in config_patches.plist in the patch-nvme github project. It makes for easy copy/paste into your own config.plist.


Creating HackrNVMeFamily*.kext with the spoofed class-code

This is described in the patch-nvme README quite clearly, but here is a quick overview with special attention to the --spoof option.

As per patch-nvme README, we must make a copy of the github project:

Code:
mkdir ~/Projects
cd Projects
git clone https://github.com/RehabMan/patch-nvme.git patch-nvme.git
cd patch-nvme.git

Since your NVMe SSD will not be using the standard class-code, but instead a non-standard one, the resulting HackrNVMeFamily*.kext must use the non-standard IOPCIClassMatch instead of the standard one.

To do this we use the --spoof option. For example, to create HackrNVMeFamily for 10.12.2:
Code:
cd ~/Projects/patch-nvme.git
./patch_nvme.sh --spoof 10_12_2

The result will be HackrNVMeFamily-10_12_2.kext which can be placed in EFI/Clover/kexts/Other for injection via Clover (installer or recovery scenario), or installed to the system volume (post-install scenario).

You can install kexts easily with Terminal. For example, to install the generated HackrNVMeFamily-10_12_2.kext:
Code:
cd ~/Projects/patch-nvme.git
sudo cp -R HackrNVMeFamily-10_12_2.kext /Library/Extensions

You can rebuild cache to verify cache can be built without error:
Code:
sudo kextcache -i /


Summary

To use the resulting HackrNVMeFamily*.kext:
- make sure the SSDT-NVMe-Pcc.aml is in EFI/Clover/ACPI/patched
- make sure existing _DSM methods at the NVMe SSD ACPI path are renamed or deleted
- install the HackrNVMeFamily*.kext or inject it via EFI/Clover/kexts

By using the SSDT, we inject a bogus class-code such that IONVMeFamily.kext does not match and therefore does not load. But because of the modified IOPCIClassMatch in the HackrNVMeFamily Info.plist created by the patch_nvme.sh script with the --spoof option, it does match on the modified class-code, and is patched for the 512 byte block size used by typical PC NVMe SSDs.

By using the class-code spoof from the very beginning, you're using the same mechanism during installation and post-installation. And once the class-code spoof is implemented, there is never any chance of IONVMeFamily.kext causing a problem. Updating is simplified as well, since you can most likely use the previous HackrNVMeFamily for the updated system until you have a chance to create a new HackrNVMeFamily after the update. And because IONVMeFamily was never deleted, it is always easy to create the new HackrNVMeFamily*.kext after the update is complete and the patch set for that version is available.


Problem Reporting

Provide a detailed and concise description of the problem.

If your drive is not recognized by the macOS/OS X installer or you are getting a panic...

Provide image from Windows Device Manager showing the ACPI namespace path of your SSD.

Attach EFI/Clover folder as ZIP (press F4 at main Clover screen before collecting). Please eliminate 'themes' directory. Provide only EFI/Clover, not the entire EFI folder.

Is it true that the only need for windows here is to read the ACPI path?
 
It may have more path components without ACPI identities. Likely behind a PCI bridge...
If you have an ioreg, it would be more clear.

I took a break for Christmas, but now I'm back at it. My most recent attempt (at installing Sierra 10.12.1 on my 950 Pro NVMe M.2 SSD) resulted in the following kernel panic: "Unable to find driver for this platform: \"ACPI\".\n"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.21.4/iokit/kernel/IOPlatformExpert.com:1667

I attached my ioreg.

Thanks again for the help.
 
Last edited:
I took a break for Christmas, but now I'm back at it. My most recent attempt (at installing Sierra 10.12.1 on my 950 Pro NVMe M.2 SSD) resulted in the following kernel panic: "Unable to find driver for this platform: \"ACPI\".\n"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.21.4/iokit/kernel/IOPlatformExpert.com:1667

I have attached my ioreg.

Thanks again for the help.

It is behind a PCI bridge...

Try this:
Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.PEG0.PEGP, DeviceObj)
    Device(_SB.PCI0.PEG0.PEGP.PCI8)
    {
        Name(_ADR, 0x00080000)
        Device(SSD0) { Name(_ADR, 0) }
    }
    Method(_SB.PCI0.PEG0.PEGP.PCI8.SSD0._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF
 
It may have more path components without ACPI identities. Likely behind a PCI bridge...
If you have an ioreg, it would be more clear.

But guessing, might be something like:
Code:
// Inject bogus class-code for NVMe SSD to prevent IONVMeFamily.kext from loading
DefinitionBlock("", "SSDT", 2, "hack", "NVMe-Pcc", 0)
{
    External(_SB.PCI0.PEG0.PEGP, DeviceObj)
    Device(_SB.PCI0.PEG0.PEGP.PCI8)
    {
        Name(_ADR, 0x08000000)
        Device(SSD0) { Name(_ADR, 0) }
    }
    Method(_SB.PCI0.PEG0.PEGP.PCI8.SSD0._DSM, 4)
    {
        If (!Arg2) { Return (Buffer() { 0x03 } ) }
        Return(Package()
        {
            "class-code", Buffer() { 0xff, 0x08, 0x01, 0x00 },
        })
    }
}
//EOF

I used this already for my previously reported attempt.

FYI: I am using a PCI bridge instead of plugging in the 950 Pro directly into one of the two available M.2 slots on the mobo since I am ultimately aiming at a multi-NVMe configuration, with the two M.2 slots populated by 960 Pro's and used exclusively for Windows 10; the 950 Pro is allocated exclusively for OS X.

Let me know if it would be helpful for me to bypass the PCI bridge for the time being and instead install it with the 950 Pro plugged directly into one of the two available M.2 slots on the mobo (the 960's won't arrive for another week or so anyways).

-----

UPDATE: My mistake, I see that the NAME is slightly different: 0x00080000 (newer post) vs. 0x08000000 (older post). I assume that means I should try again with the updated value?
 
Last edited:
Status
Not open for further replies.
Back
Top