freqVectorsEdit.sh v2.3 released

A new and improved version of freqVectorsEdit.sh is now available.

This update is required for XCPM for unsupported Processor so make sure to use this update or you will end up with the: “X86PlatformShim::start – Failed to send stepper” error.

Note: What this update does that the previous versions didn’t do is that it checks for the FrequencyVectors array, and it will add it when it is missing.

This error was a left over from the past, when Apple changed the FrequencyVectors dictionary into an array. Something that slipped off my radar and never got fixed. Should be fine now. Please confirm. Thanks!

Advertisement

XCPM for unsupported Processor…

The lack of XCPM support for my new Broadwell E processors was a bit frustrating and thus I had to do something about it. And I guess that most of you know me by now so it was just a matter of time. As in. Consider it done!

Yup. Time to say good-bye to the good old AppleIntelCPUPowerManagement.kext and the NullCPUPowerManagement.kext that served so many people for so long. Adieu my friends. They won’t be missed. LOL

Right. I can boot macOS Sierra and I see IOPPF: XCPM mode along with XCPM registered. That is pretty cool. In fact. This is amazing. Let’s go check some stuff.

sysctl -n machdep.xcpm.mode returns 1 so that is fine. Also. Running kextstat shows me that both AppleIntelCPUPowerManagement.kext and NullCPUPowerManagement.kext are missing in the list with loaded kexts. Great. Now a Geekbench v3.4.1 top score – one of four runs – of the Intel i7-6850K.

i7-6850K_macOS_Sierra_DP3_XCPM

I must admit. The longer I use this processor the more I get impressed by it. Who would have thought that? And let’s not forget. This is with XCPM so it is the more impressive. In fact. People with an old i7-5930K may keep it.

One thing though and that is that the RAM can’t run at full speed (runs like 2133MHz due to some bug) but anyway. Here is the output of AppleIntelInfo.kext

AppleIntelInfo.kext v1.5 Copyright © 2012-2016 Pike R. Alpha. All rights reserved

Settings:
------------------------------------
logMSRs............................: 1
logIGPU............................: 0
logCStates.........................: 1
logIPGStyle........................: 1
InitialTSC.........................: 0x150cbc299c8
MWAIT C-States.....................: 8480

Model Specific Registers
-----------------------------------
MSR_CORE_THREAD_COUNT......(0x35) : 0x6000C
MSR_PLATFORM_INFO..........(0xCE) : 0x20080C3BF3812400
MSR_PMG_CST_CONFIG_CONTROL.(0xE2) : 0x8402
MSR_PMG_IO_CAPTURE_BASE....(0xE4) : 0x10414
IA32_MPERF.................(0xE7) : 0x387EBCA78F
IA32_APERF.................(0xE8) : 0x3A56B9B06F
MSR_0x150..................(0x150) : 0x0
MSR_FLEX_RATIO.............(0x194) : 0xE0000
MSR_IA32_PERF_STATUS.......(0x198) : 0x23CF00002500
MSR_IA32_PERF_CONTROL......(0x199) : 0x2400
IA32_CLOCK_MODULATION......(0x19A) : 0x0
IA32_THERM_STATUS..........(0x19C) : 0x88490000
IA32_MISC_ENABLES..........(0x1A0) : 0x840089
MSR_MISC_PWR_MGMT..........(0x1AA) : 0x402000
MSR_TURBO_RATIO_LIMIT......(0x1AD) : 0x2525252525252828
IA32_ENERGY_PERF_BIAS......(0x1B0) : 0x1
MSR_POWER_CTL..............(0x1FC) : 0x2904005B
MSR_RAPL_POWER_UNIT........(0x606) : 0xA0E03
MSR_PKG_POWER_LIMIT........(0x610) : 0x7FFF80015FFF8
MSR_PKG_ENERGY_STATUS......(0x611) : 0x90C48C3
MSR_PKG_POWER_INFO.........(0x614) : 0x1700460
MSR_PP0_POWER_LIMIT........(0x638) : 0x0
MSR_PP0_ENERGY_STATUS......(0x639) : 0x0
MSR_PKGC6_IRTL.............(0x60b) : 0x0
MSR_PKG_C2_RESIDENCY.......(0x60d) : 0xA4268B844
MSR_PKG_C6_RESIDENCY.......(0x3f9) : 0x79FDD64350
IA32_TSC_DEADLINE..........(0x6E0) : 0x150CD144AC8

CPU Ratio Info:
------------------------------------
CPU Low Frequency Mode.............: 1200 MHz
CPU Maximum non-Turbo Frequency....: 3600 MHz
CPU Maximum Turbo Frequency........: 4000 MHz
CPU P-States [ 33 37 (40) ]
CPU C6-Cores [ 0 2 5 7 9 10 ]
CPU P-States [ 31 33 37 (40) ]
CPU C6-Cores [ 0 2 3 4 5 7 9 10 ]
CPU P-States [ (12) 31 33 37 40 ]
CPU C6-Cores [ 0 1 2 3 4 5 6 7 9 10 11 ]
CPU P-States [ (12) 25 31 33 37 40 ]
CPU P-States [ 12 25 29 31 33 37 (40) ]
CPU P-States [ 12 25 29 30 31 33 37 (40) ]
CPU P-States [ 12 25 28 29 30 31 33 37 (40) ]
CPU C6-Cores [ 0 1 2 3 4 5 6 7 8 9 10 11 ]
CPU P-States [ (12) 22 25 28 29 30 31 33 37 40 ]
CPU P-States [ (12) 21 22 25 28 29 30 31 33 37 40 ]
CPU P-States [ (12) 21 22 23 25 28 29 30 31 33 37 40 ]
CPU P-States [ (12) 20 21 22 23 25 28 29 30 31 33 37 40 ]
CPU P-States [ 12 20 21 22 23 25 28 29 30 31 32 33 37 (40) ]
CPU P-States [ 12 20 21 22 23 25 28 29 30 31 32 33 37 39 (40) ]
CPU P-States [ 12 20 21 22 23 25 27 28 29 30 31 32 33 37 39 (40) ]
CPU P-States [ (12) 17 20 21 22 23 25 27 28 29 30 31 32 33 37 39 40 ]
CPU P-States [ (12) 16 17 20 21 22 23 25 27 28 29 30 31 32 33 37 39 40 ]
CPU P-States [ (12) 16 17 18 20 21 22 23 25 27 28 29 30 31 32 33 37 39 40 ]
CPU P-States [ 12 16 17 18 19 20 21 22 23 25 27 28 29 30 31 32 33 37 39 (40) ]
CPU P-States [ 12 16 17 18 19 20 21 22 23 25 27 28 29 30 31 32 33 37 38 39 (40) ]
CPU P-States [ 12 16 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 37 38 39 (40) ]
CPU P-States [ 12 16 17 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 36 37 38 39 (40) ]
CPU P-States [ (12) 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 36 37 38 39 40 ]
CPU P-States [ 12 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 (40) ]
CPU P-States [ 12 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 (40) ]
CPU P-States [ (12) 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 ]
CPU P-States [ 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 (40) ]
CPU P-States [ (12) 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ]

Hmm. C3 is missing. Seems like I forgot to enable C3 for Broadwell E processors and thus I have to fix this and re-compile the kext. On a second thought. The redirection bits are not set in MSR 0xE2 so this is expected result.

But both MSR_PKG_C2_RESIDENCY and MSR_PKG_C6_RESIDENCY are non-zero. A sweet spot.

Update: I don’t have a lot of time, but I also do not want to let you wait so here you have it!

//
// kernel location 0x1fb451 (0xE9 in DP2/DP3/DP4, 0xF1 in DP1) _cpuid_set_info
//
// Broadwell E (0x4F)	-> Broadwell (0x47)	=> 0x4F-0x47 = 0x08	-> change 0xE9 into 0xE1
// Haswell E (0x3F)		-> Haswell (0x3C)	=> 0x3F-0x3C = 0x03	-> change 0xE9 into 0xE6
// Ivy Bridge E (0x3E)	-> Ivy Bridge (0x3A)	=> 0x3E-0x3A = 0x04	-> change 0xE9 into 0xE5

../..

//
// kernel location 0x22a422 (0xC4 in DP2/DP3/DP4, 0x?? in DP1) _xcpm_bootstrap
//
// Broadwell E (0x4F)	-> Broadwell (0x47)	=> 0x4F-0x47 = 0x08	-> change 0xC4 into 0xBC
// Haswell E (0x3F)		-> Haswell (0x3C)	=> 0x3F-0x3C = 0x03	-> change 0xC4 into 0xC1
// Ivy Bridge E (0x3E)	-> Haswell (0x3C)	=> 0x3E-0x3C = 0x02	-> change 0xC4 into 0xC2
//
// Broadwell E (0x4F)	-> Haswell (0x3C)	=> 0x4F-0x3C = 0x13	-> change 0xC4 into 0xB1

../..

//
// If MSR(0xE2) is locked (bit-15 is set) then also change
//
// kernel location 0x220b30 and 0x220b5f in _xcpm_idle from 0x0f30 (wrmsr) to 0x9090 (nop nop).

//
// Additionally (if booting results in a immediate reboot)
//
// kernel location 0x22a820 change 0x55 into 0xC3 (ret) to stop the KP.
//

Update: DP4 is now available and the byte patterns are still the same, but the locations have changed to: 0x1f8d81, 0x227d32, 0x21e440, 0x21e46f and 0x228130 (same order as above).

Update-2: DP5 is now available and the byte patterns are still the same, but the locations have changed to: 0x1f8930, 0x228af0, 0x21eff0, 0x21f01f and 0x228f50 (same order as above).

Update-3: DP6 is now available and the byte patterns are still the same, but the locations have changed to: 0x1f7cc0, 0x227f30, 0x21e430, 0x21e45f and 0x428390 (same order as above).

Update-4: DP7 is now available and the byte patterns are still the same, but the locations have changed to: 0x1f8d71, 0x227fc2, 0x21e460, 0x21e48f and 0x2283c0 (same order as above).

The patches can be done in at least three different ways and I picked what I think is the easiest one to understand. So I hope. Also. I don’t use FakeCPUID – nor Clover for that matter – with my patches, but some people using Clover reported a hang. For them it won’t boot without FakeCPUID (thanks to giacomoleopardo for the update).

Update: Owners of Ivy Bridge E or Haswell E processors do not need to patch the switch table used by _cpuid_set_info, because Apple already took care of it. Anyway. Have a look at this table:

switchtable_cpuid_set_info

The offset for the Broadwell E processor is missing in this table. There is an address but that jumps to a location for unsupported processors, which is why we need a patch for the Broadwell E processor (the red arrow shows you what we do with the patch) but I think that Apple will fix this with a future update of macOS Sierra so that we also no longer need to patch the table for Broadwell E processors.

Please note that the table was converted from the original one in the kernel, which looks like this:

0xffffff80003fbc6c	dd	0xfffff82c, 0xfffff831, 0xfffff831, 0xfffff7fb
0xffffff80003fbc7c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff7fb
0xffffff80003fbc8c	dd	0xfffff7fb, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbc9c	dd	0xfffff831, 0xfffff831, 0xfffff809, 0xfffff831
0xffffff80003fbcac	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff810
0xffffff80003fbcbc	dd	0xfffff831, 0xfffff809, 0xfffff810, 0xfffff7fb
0xffffff80003fbccc	dd	0xfffff809, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbcdc	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbcec	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff817
0xffffff80003fbcfc	dd	0xfffff831, 0xfffff802, 0xfffff81e, 0xfffff817
0xffffff80003fbd0c	dd	0xfffff802, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbd1c	dd	0xfffff831, 0xfffff831, 0xfffff802, 0xfffff802
0xffffff80003fbd2c	dd	0xfffff81e, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbd3c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff825
0xffffff80003fbd4c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbd5c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbd6c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff831
0xffffff80003fbd7c	dd	0xfffff831, 0xfffff831, 0xfffff831, 0xfffff825

Update: DP4 is now available and while the table is still the same, the location of it has changed to: 0xffffff80003f959c

Update-2: DP5 is now available and while the table is still the same, the location of it has changed to: 0xffffff8000428cbc

Update-3: DP7 is now available and while the table is still the same, the location of it has changed to: 0xffffff80003f958c

And here is what I did with the values. Let’s take the last value (0xfffff825 ) as an example:

0xffffffff - (0xfffff825 - 0x01) = 0x7DB

I then used the value as a negative offset, and we do that because the table is located at a higher memory address, so here we go:

0xffffff80003fbc6c - 0x7DB = 0xffffff80003FB491

Great. Now look at this disassembled code snippet:

0xffffff80003fb43b	movzwl	0x6fcc42(%rip), %eax
0xffffff80003fb442	xorl	%ebx, %ebx				// Zero out %ebx
0xffffff80003fb444	movzbl	%al, %ecx
0xffffff80003fb447	cmpl	$0x6, %ecx				// Check CPU family
0xffffff80003fb44a	jne		0xffffff80003fb49d

0xffffff80003fb44c	movzbl	%ah, %eax
0xffffff80003fb44f	addl	$-0x17, %eax			// Lower model number (example: 0x5e -> 0x4f)
0xffffff80003fb452	cmpl	$0x47, %eax				// Check for unsupported model numbers
0xffffff80003fb455	ja		0xffffff80003fb49d		// Jump if greater than 0x47 (unsupported model numbers)

0xffffff80003fb457	leaq	0x80e(%rip), %rcx		// Store address of case table 0xffffff80003fbc6c into %rcx
0xffffff80003fb45e	movslq	(%rcx,%rax,4), %rax		// Move and sign-extend 32-bit value from switch table in %rax 
0xffffff80003fb462	addq	%rcx, %rax				// Example: 0xffffff80003fbc6c - 0x7db = 0xffffff80003fb491 (CPUFAMILY_INTEL_SKYLAKE)
0xffffff80003fb465	jmpq	*%rax					// Jump to target address

0xffffff80003fb467	movl	$0x6b5a4cd2, %ebx		// CPUFAMILY_INTEL_NEHALEM
0xffffff80003fb46c	jmp		0xffffff80003fb49d

0xffffff80003fb46e	movl	$0x10b282dc, %ebx		// CPUFAMILY_INTEL_HASWELL
0xffffff80003fb473	jmp		0xffffff80003fb49d

0xffffff80003fb475	movl	$0x573b5eec, %ebx		// CPUFAMILY_INTEL_WESTMERE
0xffffff80003fb47a	jmp		0xffffff80003fb49d

0xffffff80003fb47c	movl	$0x5490b78c, %ebx		// CPUFAMILY_INTEL_SANDYBRIDGE
0xffffff80003fb481	jmp		0xffffff80003fb49d

0xffffff80003fb483	movl	$0x1f65e835, %ebx		// CPUFAMILY_INTEL_IVYBRIDGE
0xffffff80003fb488	jmp		0xffffff80003fb49d

0xffffff80003fb48a	movl	$0x582ed09c, %ebx		// CPUFAMILY_INTEL_BROADWELL
0xffffff80003fb48f	jmp		0xffffff80003fb49d

0xffffff80003fb491	movl	$0x37fc219f, %ebx		// CPUFAMILY_INTEL_SKYLAKE
0xffffff80003fb496	jmp		0xffffff80003fb49d

0xffffff80003fb498	movl	$0x78ea4fbc, %ebx		// CPUFAMILY_INTEL_PENRYN
0xffffff80003fb49d	movl	%ebx, 0x6fcd35(%rip)
0xffffff80003fb4a3	cmpl	$0x0, 0x6fcb6e(%rip)
0xffffff80003fb4aa	je		0xffffff80003fb4c3

Our calculated address is spot on. Now let’s have a look at the switch table that is used by _xcpm_bootstrap in macOS Sierra DP3:

0xffffff800042a58c         dd         0xfffffeac, 0xfffffec7, 0xfffffeb8, 0xfffffeb8 
0xffffff800042a59c         dd         0xfffffeb8, 0xfffffeb8, 0xfffffeb8, 0xfffffeb8
0xffffff800042a5ac         dd         0xfffffeb8, 0xfffffed3, 0xfffffee9, 0xffffff0a
0xffffff800042a5bc         dd         0xfffffeb8, 0xfffffeb8, 0xfffffeb8, 0xfffffeb8
0xffffff800042a5cc         dd         0xfffffeb8, 0xfffffeb8, 0xffffff16, 0xfffffeb8
0xffffff800042a5dc         dd         0xfffffeb8, 0xfffffeb8, 0xfffffeb8, 0xfffffeb8
0xffffff800042a5ec         dd         0xfffffeb8, 0xfffffeb8, 0xfffffeb8, 0xfffffeb8
0xffffff800042a5fc         dd         0xfffffeb8, 0xfffffeb8, 0xfffffeb8, 0xfffffeb8
0xffffff800042a60c         dd         0xfffffeb8, 0xfffffeb8, 0xffffff2c

Update: DP4 is now available and while the table is still the same, the location of it has changed to: 0xffffff8000427e9c

Update: DP7 is now available and while the table is still the same, the location of it has changed to: 0xffffff800042812c

A shorter table with 34 instead of 72 values, but the idea here is the same. And with the same kind of table conversion we get this:

SwitchTable_xcmp_bootstrap

This time the table starts at 0x3c instead of 0x17 and there are no addresses for the Ivy Bridge E, Haswell E and Broadwell E processors, again, for the same reason; it jumps to a location for processors that do not support XCPM.

Speaking about that address. All locations in the switch table in the kernel with the value 0xfffffeb8 jump to the same location for unsupported processors and here is how to calculate the offset and target address for the jmp instruction:

0xffffffff - (0xfffffeb8-0x01) = 0x148
0xffffff800042a58c - 0x148 = 0xffffff800042a444

And looking at the disassembled code snipped of _xcpm_bootstrap that is where XCPM gets disabled:

0xffffff800042a420	addl	$-0x3c, %ebx					// Lower model number (example: 0x5e -> 0x22(34)
0xffffff800042a423	cmpl	$0x22, %ebx						// Check for unsupported models
0xffffff800042a426	ja		0xffffff800042a444				// Jump if greater than 0x22 (unsupported model numbers)

0xffffff800042a428	leaq	0x15d(%rip), %rax				// Store address of case table 0xffffff800042a58c into %rcx
0xffffff800042a42f	movslq	(%rax,%rbx,4), %rcx				// Move and sign-extend 32-bit value from switch table in %rax 
0xffffff800042a433	addq	%rax, %rcx						// Example: 0xffffff800042a58c - 0xd4 = 0xffffff80000x42a4b8 (Skylake)
0xffffff800042a436	jmpq	*%rcx							// Jump to target address

0xffffff800042a438	movl	$0x4, _xcpm_cpu_model(%rip)		// case 0: Haswell (0x3c-0x3c=0)
0xffffff800042a442	jmp		0xffffff800042a47f

0xffffff800042a444	movl	$0x0, _xcpm_mode(%rip)			// case 33: xcpm_mode = 0 (XCPM disabled)
0xffffff800042a44e	jmp		0xffffff800042a580

0xffffff800042a453	movl	$0x80, _xcpm_cpu_model(%rip)	// case 1: Broadwell (0x3d-0x3c=1)
0xffffff800042a45d	jmp		0xffffff800042a4ac

0xffffff800042a45f	movl	$0x10, _xcpm_cpu_model(%rip)	// case 9: Haswell-ULT (0x45-0x3c=9)
0xffffff800042a469	movl	$0x1, 0x602981(%rip)
0xffffff800042a473	jmp		0xffffff800042a47f

0xffffff800042a475	movl	$0x8, _xcpm_cpu_model(%rip)		// case 10: Crystalwell (0x46-0x3c=10)
0xffffff800042a47f	movl	$0x1, 0x602973(%rip)
0xffffff800042a489	movq	$0x0, 0x6029dc(%rip)
0xffffff800042a494	jmp		0xffffff800042a50c

0xffffff800042a496	movl	$0x40, _xcpm_cpu_model(%rip)	// case 11: Broadwell-H (0x47-0x3c=11)
0xffffff800042a4a0	jmp		0xffffff800042a50c

0xffffff800042a4a2	movl	$0x200, _xcpm_cpu_model(%rip)	// case 18: Skylake (0x4e-0x3c=18)
0xffffff800042a4ac	movl	$0x1, 0x60293e(%rip)
0xffffff800042a4b6	jmp		0xffffff800042a50c

0xffffff800042a4b8	movq	0x6cebf1(%rip), %rdi			// case 34: Skylake (0x5e-0x3c=34)
0xffffff800042a4bf	testq	%rdi, %rdi
0xffffff800042a4c2	jne		0xffffff800042a4d9

0xffffff800042a4c4	movq	0x6999b5(%rip), %rax
0xffffff800042a4cb	movq	0x488(%rax), %rdi
0xffffff800042a4d2	movq	%rdi, 0x6cebd7(%rip)

0xffffff800042a4d9	addq	$0x2, %rdi
0xffffff800042a4dd	movl	$0x2, %esi
0xffffff800042a4e2	callq	0xffffff8000402580
0xffffff800042a4e7	movzwl	%ax, %eax
0xffffff800042a4ea	cmpl	$0x1910, %eax
0xffffff800042a4ef	movl	$0x2000, %eax
0xffffff800042a4f4	movl	$0x1000, %ecx
0xffffff800042a4f9	cmovel	%eax, %ecx
0xffffff800042a4fc	movl	%ecx, _xcpm_cpu_model(%rip)
0xffffff800042a502	movl	$0x0, 0x6028e8(%rip)

This routine has no matching case number for the Ivy Bridge E, Haswell E and Broadwell E processors. That is why we lower the model number to make it match with a supported processors model. Like we are using a normal Ivy Bridge, Haswell or Broadwell processor. A simple but effective trick it seems.

I hope that my explanation about all this helps you to understand what we are doing.

Edit: Make sure that you either use a SMBIOS model/board-id with FrequencyVectors data in its plist, or patch it with help of freqVectorsEdit.sh v2.3.

You can verify that the FrequencyVector data is loaded with help of sysctl -n machdep.xcpm.vectors_loaded_count

Tips:

1.) The X86PlatformPlugin.kext will only load with the plugin-type property is set on the first logical CPU. This however is not enough to enable XCPM mode. No. You may still use AppleIntelCPUPowerManagement.kext Even when X86PlatformShim.kext is loaded.

2.) The FrequencyVectors data in the plist is used to configure power management, and is not the same for all models/board-ids. Please use one that works for your setup.

3.) If sysctl -n machdep.xcpm.vectors_loaded_count returns 0 then the FrequencyVectors data is not being used. Backup the plist for your board-id and replace it with a different plist.

4.) If you use ssdtPRGen.sh to generate your ssdt_pr.aml then make sure to use the -turbo [top-turbo-frequency] argument for overclocked setups.

5.) Check for XCPM related errors at boot time. Like this: X86PlatformShim::start – Failed to send stepper. You got to fix errors or things may not work properly.

TODOs:

1.) Fix LFM frequency (fixed to 800MHz).
2.) Figure out what MSRs trigger a reboot and only block them. Not all other supported MSRs as well.

Intel i7-6850K Geekbench results

Yesterday I blogged about my Intel i7-6800K Geekbench results and I said to replace the i7-6800K with the i7-6850K to see what that brings. Well. It’s not just the higher clock rate (3.6GHz versus 3.4GHz) but also the maximum turbo frequency (4GHz versus 3.8GHz) and some headroom for 200MHz extra OC.

Where is the Geekbench 3.4.1 result? Right. Here it is. Enjoy.

Back to work now…

Edit: I forgot to tell you something. I did not need VoodooTSCSync.kext with the i7-6800K and I also don’t need it with the i7-6850K so that is good news.

Intel i7-6800K Geekbench results

I was fairly disappointed by the first Geekbench result but after a lot of changes and overclocking… todays Geekbench v3.4.1 score results went up from a low 2958 to a much higher score of 4229. Well. That’s more like it. No slouch after all 😉

But it doesn’t stop here. Nope. The Geekbench 3 results will be even higher when Asus has solved the G.Skill incompatibility bug in the BIOS – I have 128 GB running at a speed of 2133MHz instead of 3200MHz. Imagine what that will do to benchmark scores 😉

And there is another bug in the 601 BIOS. At least that’s how I see it. This one blocks me from enabling the C3 and C6 C-states – options are greyed out and MSR(0xE2) is missing the bits. The problem appears to be the CPU Ratio setting in the BIOS, since changing it from Auto to anything else (Sync All Cores or Per Core) basically disables the C-States setting.

Ok. I found a workaround for it, after fiddling with the CPU Core Ratio setting, but I love to see a real fix for it. Perhaps in the next BIOS update? One that doesn’t set the lock bit of said MSR?

On a side note. Why do I keep seeing the error that tells me that over clocking failed… and I have to press F1, when in fact I didn’t even – at that time – OC my rig?

Thanks Asus!

p.s. The i7-6800K is not a typo. Yes. I also have a i7-6850K waiting for this motherboard, and we will install it (again) sometime next week.

Asus X99-E (WS) with i7-6850K

I have an Asus X99-E (WS) motherboard for testing laying around, for ages, that I like to use with Broadwell-E processors (i7-6800K and i7-6850K) and I’d like to use this setup for power management testing, but the guy who is installing the hardware said that it reboots when the kernel should be launched.

What is he missing?

Please be aware that we don’t use Clover… so we can only use raw patch data.

Update: I went to the shop this morning and checked the setup myself and found two major errors.

1.) Error in com.apple.Boot.plist; “Boot Graphics” was used like it was “Graphics Mode” (triggers a reboot).

2.) Error in the BIOS; -> CPU Configuration -> Enable Execution Bit was set to ‘Disabled’ and that is known to trigger a reboot.

So problem solved? Err. Not exactly. Sure. The immediate reboot is fixed, but now I am looking at the ‘PCI configuration error’. Patching the IOPCIFamily binary didn’t help. I also see that AppleIntelCPUPowerManagement.kext is loaded. Oh well…

Update-2: We disabled the XHCI controller in the BIOS (the AsMedia 3.1 USB controller was already disabled) and now we are seeing this: “Still waiting for root device” error. One step closer, but USB is acting up. Handoff is enabled in the BIOs so that should not be a problem, right?

Update-3: I was getting errors (read the comments) and the value was rather suspicious and thus I checked the on-line manual and found this:

Above 4G Decoding [Disabled]

This item allows you to decode the 64-bit capable devices above 4G address space. Ensure that your system supports 64-bit PCI decoding. Configuration options: [Disabled] [Enabled]

We had this setting on Enabled and changing it to Disabled solved the errors. The macOS Sierra installation process is now running done and everything looks alright.

Update-4: Performance is rubbish! AppleLPC.kext won’t load. Even after adding the missing device-id to the Info.plist. Started to load without a single extra change (no prelinkedkernel used). But seriously. I have yet to figure out why people would want the i7-6800K six core processor. The turn offs for me are:

1.) 140 Watt TDP.
2.) Slow 3.4 GHz base frequency.
3.) Limited turbo support (only 200 MHz extra).
4.) MS Windows only ‘Turbo Boost Max 3 Technology’.

The Intel Turbo Boost Max 3 Technology is mind boggling limited and has no future. It only adds a new layer of complexity. We don’t need that. Your processors should deliver the best performance, on request, without the need of (MS Windows only) driver(s).

Update-5: I ran AppleIntelinfo.kext (the KP was fixed in the latest update) and what we see here is that while MSR_TURBO_RATIO_LIMIT (0x1AD) is setup correctly by the BIOS (0x2323232425262728) bit only really triggers the first turbo frequency. This was with a mild manual OC to 4.0 GHz. And even then only 3.5 GHz was reported, and 4.0 GHz only once.

Another error is that the IA32_ENERGY_PERF_BIAS MSR (0x1B0) is zero – this value should be at least 1 and not be higher than 15. At least for XCPM mode.

Simple Skylake USB Fix (no kexts required)

Back in December 2015 I blogged about My Initial ElCapitan USB workaround and yeah the nullifying of Device (XHC) was nothing more than a hack. I also forgot to share what it is that I use these days. Well. Let me start with a screenshot:
Skylake_UMAP_Patch
This shows you that all my USB 2.0 and USB 3.0 ports are enabled. I did that with this tiny SSDT:

DefinitionBlock ("ssdt_usb.aml", "SSDT", 2, "APPLE ", "Xhci", 0x00001000)
{
    External (\UMAP, IntObj)

    Scope (\_SB)
    {
        Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            Store ("Method \\_SB._INI Called", Debug)
            Store (0xf2ff, \UMAP)
        }
    }

Now you say; “Ok. So you store a value of 0xf2ff into UMAP, but what is that?

Good question. Let’s first have a look at how UMAP is defined in the Skylake DSDT:

    Name (UMAP, 0xFFFF)

This value can, in theory, enable up to 32 USB ports since the bits are linked to physical ports (USB 2.0 and USB 3.0 on the same port share one and the same bit).

My GA-B150M-D3H (DDR4) motherboard has ten USB 2.0 (HSnn) ports and six USB 3.0 (SSnn) ports. Giving me a total of sixteen ports. We also know that there is a limit of fifteen ports, so I had one too many, but I don’t use one of the headers on the motherboard and thus I have fifteen active ports. In short. I don’t need a port limit patch.

Let’s continue with some essential code which I found in one of the SSDT’s (xh_rvp10):

    Scope (\_SB.PCI0.XHC.RHUB.HS01)
    {
        Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
        {
            If (LEqual (And (UMAP, One), One))
            {
                If (LEqual (And (HUBC, One), One))
                {
                    Return (GUPC (Zero))
                }
                Else
                {
                    Return (GUPC (One))
                }
            }
            Else
            {
                Return (GUPC (Zero))
            }
        }

        Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
        {
            If (LEqual (And (UMAP, One), One))
            {
                If (LEqual (And (HUBC, One), One))
                {
                    Return (GPLD (Zero, Zero))
                }
                Else
                {
                    Return (GPLD (One, One))
                }
            }
            Else
            {
                Return (GPLD (Zero, Zero))
            }
        }
    }

What this does is that it checks bit-0 of UMAP and when that is set/high (read: has a value of one) then the port is enabled. The same kind of code snippet is also used for port SS01 (USB 3.0):

    Scope (\_SB.PCI0.XHC.RHUB.SS01)
    {
        Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
        {
            If (LEqual (And (UMAP, One), One))
            {
                If (LEqual (And (HUBC, One), One))
                {
                    Return (GUPC (Zero))
                }
                Else
                {
                    Return (GUPC (One))
                }
            }
            Else
            {
                Return (GUPC (Zero))
            }
        }

        Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
        {
            If (LEqual (And (UMAP, One), One))
            {
                If (LEqual (And (HUBC, One), One))
                {
                    Return (GPLD (Zero, Zero))
                }
                Else
                {
                    Return (GPLD (One, One))
                }
            }
            Else
            {
                Return (GPLD (Zero, Zero))
            }
        }
    }

In fact. This kind of code snippets is used for all USB ports. The mask value is different for each port. The two sub-routines (GUPC and GPLD) are used to prevent code duplication.

We also need to know the value of HUBC and that is defined in the DSDT as:

    Name (HUBC, Zero)

Now we know the value of HUBC and thus we can strip the routine a little. No. We are not going to do that in the ACPI tables. This is only meant to help you understand what is does, and here is an example:

    Scope (\_SB.PCI0.XHC.RHUB.XXNN)
    {
        Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
        {
            If (LEqual (And (UMAP, One), One))
            {
                Return (GUPC (One))
            }
            Else
            {
                Return (GUPC (Zero))
            }
        }

        Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
        {
            If (LEqual (And (UMAP, One), One))
            {
                Return (GPLD (One, One))
            }
            Else
            {
                Return (GPLD (Zero, Zero))
            }
        }
    }

In short. Method _UPS returns Return (GUPC (One)) for active/enabled ports and Return (GUPC (Zero)) for inactive/disabled ports.

Edit: I no longer use a tiny SSDT but let RevoBoot handle it for me, but I don’t know if Clover can do this. In yes, then you want
08 55 4D 41 50 0B FF FF
in your DSDT.aml to be replaced with the value that you need for your hardware. On the other hand. You may already use a SSDT where you can add Method (_INI) {...}
or use a one liner to set the value. To me the most simple solution there is.

Long story short. If you want a real vanilla solution, then use this instead of (unsigned) third party kexts 😉

Have fun!

Say hello to new logging in Sierra…

One thing that I don’t hear people talk about is Apples new unified (system wide) logging system, introduced with Sierra, and that to me is odd, because it is totally different. I mean. You can forget about terminal commands like cat /var/log/system.log and we (developer, hackers et all) need to get ready for Sierra. We need to embrace sudo log (see man log) and get accustomed to all new (sub) commands and filter options. And quite a few I tell you, so start reading this document and Predicate Format String Syntax.

The Console app in the Utilities folder has also been updated, but I never really liked it, and I can’t tell (yet) if that will change. Always been more a keyboard hammer type of person. Thanks to my father I guess.

Nope. I am not going to retype the man page. You can read it yourself. Just type man log in a terminal window and start playing with your new toy 😉

p.s. Let me know if and what (sub) command you like use most…

IONVMeFamily.kext changes in Sierra DP2 (build 16A239j)

I have installed the Sierra DP2 update (build 16A239j) and the IONVMeFamily.kext bin patch data is unchanged, still working, but there are a couple of other (minor) changes that you may have missed – Apple now calls _bzero for some buffers (five times).

IONVMeBlockStorageDevice::doUnmap(IOBlockStorageDeviceExtent*, unsigned int, unsigned int)

0000000000006306	movq	%r15, %rdi
0000000000006309	callq	*0x2e0(%rax)
000000000000630f	movl	$0x1000, %esi
0000000000006314	movq	%rax, %rdi
0000000000006317	callq	_bzero
000000000000631c	movq	(%r15), %rax

IONVMeController::PolledIdentifyController(bool, unsigned int)

000000000000c185	movq	%r14, %rdi
000000000000c188	callq	*0x2e0(%rax)
000000000000c18e	movl	$0x1000, %esi
000000000000c193	movq	%rax, %rdi
000000000000c196	callq	_bzero
000000000000c19b	movq	(%r14), %rax

IONVMeController::IdentifyController()

000000000000c6e6	testq	%rbx, %rbx
000000000000c6e9	je	0xc784
000000000000c6ef	movq	(%rbx), %rax
000000000000c6f2	movq	%rbx, %rdi
000000000000c6f5	callq	*0x2e0(%rax)
000000000000c6fb	movl	$0x1000, %esi
000000000000c700	movq	%rax, %rdi
000000000000c703	callq	_bzero
000000000000c708	movq	(%rbx), %rax

IONVMeController::CheckWriteProtection()

000000000000d8c2	movq	%rbx, %rdi
000000000000d8c5	callq	*0x2e0(%rax)
000000000000d8cb	movl	$0x1000, %esi
000000000000d8d0	movq	%rax, %rdi
000000000000d8d3	callq	_bzero
000000000000d8d8	movq	(%rbx), %rax

IONVMeController::SetSystemRequirements(unsigned char)

000000000000e891	movq	(%rbx), %rax
000000000000e894	movq	%rbx, %rdi
000000000000e897	callq	*0x9f0(%rax)
000000000000e89d	testl	%eax, %eax
000000000000e89f	je	0xe8bc
000000000000e8a1	movq	(%rbx), %r8
000000000000e8a4	movl	%eax, %edx
000000000000e8a6	leaq	0xe451(%rip), %rsi ## literal pool for: "IOMinimumSaturationByteCount"
000000000000e8ad	movl	$0x20, %ecx
000000000000e8b2	movq	%rbx, %rdi
000000000000e8b5	callq	*0x280(%r8)

IONVMeController::GetSaturationByteCountKey()

000000000000f264	pushq	%rbp
000000000000f265	movq	%rsp, %rbp
000000000000f268	pushq	%rbx
000000000000f269	pushq	%rax
000000000000f26a	xorl	%ebx, %ebx
000000000000f26c	testb	$0x10, 0x100(%rdi) ## check for built-in device
000000000000f273	je	0xf2c5
000000000000f275	movq	0xc0(%rdi), %rdi ## check device state
000000000000f27c	testq	%rdi, %rdi
000000000000f27f	je	0xf2c5
000000000000f281	movq	(%rdi), %rax
000000000000f284	leaq	0xdc12(%rip), %rsi ## literal pool for: "IOPCIExpressLinkStatus"
000000000000f28b	callq	*0x2b8(%rax)
000000000000f291	movq	0xfdd8(%rip), %rcx
000000000000f298	movq	(%rcx), %rsi
000000000000f29b	movq	%rax, %rdi
000000000000f29e	callq	0xf2a3
000000000000f2a3	testq	%rax, %rax
000000000000f2a6	je	0xf2c5
000000000000f2a8	movq	(%rax), %rcx
000000000000f2ab	movq	%rax, %rdi
000000000000f2ae	callq	*0x148(%rcx)
000000000000f2b4	andl	$0x3ff, %eax
000000000000f2b9	cmpl	$0x43, %eax
000000000000f2bc	sete	%al
000000000000f2bf	movzbl	%al, %ebx
000000000000f2c2	shll	$0x17, %ebx
000000000000f2c5	movl	%ebx, %eax
000000000000f2c7	addq	$0x8, %rsp
000000000000f2cb	popq	%rbx
000000000000f2cc	popq	%rbp
000000000000f2cd	retq

AppleNVMeSMARTUserClient::ProductionTunnel(OSObject*, void*, IOExternalMethodArguments*)

0000000000018041	movq	%rbx, %rdi
0000000000018044	callq	*0x2e0(%rax)
000000000001804a	movl	$0x1000, %esi
000000000001804f	movq	%rax, %rdi
0000000000018052	callq	0x18057
0000000000018057	movq	_bzero

There are of course a lot more changes, but they are all address related so they are unimportant to us. More importantly is the fact that we have a new property called IOMinimumSaturationByteCount. Look here.

IOMinimumSaturationByteCount

The exact meaning of it, for us, has yet to be determined.

Edit: Text moved and screenshot added.

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"
                            }
                        })
                    }
                }
            }
        }