Teaching Apple programmers something…

Hola! I looked at the latest XNU source code, in particular tsc.c and tried to locate a new Skylake specific ARTFrequency property (for OS X) and this is what I have found:

	case CPUFAMILY_INTEL_SKYLAKE: {
		/*
		 * SkyLake and later has an Always Running Timer (ART) providing
		 * the reference frequency. CPUID leaf 0x15 determines the
		 * rationship between this and the TSC frequency expressed as
		 *   -	multiplier (numerator, N), and 
		 *   -	divisor (denominator, M).
		 * So that TSC = ART * N / M.
		 */
		cpuid_tsc_leaf_t *tsc_leafp = &cpuid_info()->cpuid_tsc_leaf;
		uint64_t	 N = (uint64_t) tsc_leafp->numerator;
		uint64_t	 M = (uint64_t) tsc_leafp->denominator;
		uint64_t	 refFreq;

		refFreq = EFI_get_frequency("ARTFrequency");
		if (refFreq == 0)
			refFreq = BASE_ART_CLOCK_SOURCE;

		assert(N != 0);
		assert(M != 1);
		tscFreq = refFreq * N / M;
		busFreq = tscFreq;		/* bus is APIC frequency */

		kprintf(" ART: Frequency = %6d.%06dMHz, N/M = %lld/%llu\n",
			(uint32_t)(refFreq / Mega),
			(uint32_t)(refFreq % Mega), 
			N, M);

		break;
	    }

The numerator and denominator values are read in with help of this code snippet from cpuid.c – CPUID leaf 0x15 exposes the relationship between ART and TSC.

	if (info_p->cpuid_max_basic >= 0x15) {
		/*
		 * TCS/CCC frequency leaf:
		 */
		cpuid_fn(0x15, reg);
		info_p->cpuid_tsc_leaf.denominator = reg[eax];
		info_p->cpuid_tsc_leaf.numerator   = reg[ebx];

		DBG(" TSC/CCC Information Leaf:\n");
		DBG("  numerator     : 0x%x\n", reg[ebx]);
		DBG("  denominator   : 0x%x\n", reg[eax]);
	}

The problem I am having with it is that one Intel engineer wrote that the numerator is always 2 and can be found in register eax. Really? Well. I checked it and did indeed find a value of 2 in register eax. Register ebx holds a value of 284 (for the Intel i7-6700) and if I use it like this:

((24000000 * 284) / 2) = 3408000000

or this:

24000000 * (284 / 2) = 3408000000

Then all is fine. A next step is to get the bus frequency by dividing the result by 34 (the CPU ratio) which gives me a value of (roughly) 100 MHz. Exactly what I am looking for. And almost the same value that is used for the FSBFrequency property in OS X. But wait. Why did the Intel engineer say that the numerator (N) is always 2, when in fact it is 284? Turns out that M is 2. Great. Now I look like an jerk, because he was talking about getting M:

tscFreq = 3408000000 // Assuming that we are using an Intel i7-6700
refFreq = BASE_ART_CLOCK_SOURCE // 24000000
N = 2 // value of register eax
M = ((tscFreq * N) / 24000000)

I on the other hand was trying to verify my findings for the TSC/bus frequencies, and he said not to comment on other peoples code. Great.

Edit: I redacted my blog article after it became clear that I was wrong. I did’t want to start off on the wrong foot, but I should have checked the Intel Software Developer Manual before posting my blog article. A stupid error on my side, because what Apple does – by following the Intel Software Developer Manual (Vol. 2A 3-187) – is spot on. The Intel engineer was also right, but our conversation got mixed up and I ended up being dead wrong, for which I apologise. Feeling pretty stupid now. What a joy LOL

AppleIntelSKLGraphicsFramebuffer.kext mods…

I presume that most people are using the following frame buffer data:

0000 1219 0103 0303 0000 0004 0000 2002
0000 5001 0000 0060 6C05 0000 6C05 0000
0000 0000 0000 0000 FF00 0000 0100 0000
4000 0000 0105 0900 0004 0000 0705 0000
0204 0A00 0004 0000 0705 0000 0306 0A00
0004 0000 0705 0000 0601 0000 0000 0800
0200 0000 0400 0000 80DF 1710 0000 0000
7805 0000 D205 0000 4006 0000 0000 0000
0000 0000 0000 0000

Or a slightly modified one, but I use this (was like the one above)

0300 1219 0001 0101 0000 0002 0000 3001
0000 0000 0000 0060 9914 0000 9914 0000
0000 0000 0000 0000 FF00 0800 0002 0000
4000 0000 FF05 0000 0100 0000 4000 0000
FF04 0000 0100 0000 4000 0000 FF00 0000
0100 0000 4000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000

Note that pretty much every value was changed, including the framebuffer ID, the total number of frame buffers, planes and ports – changed to one. Everything done on purpose. To show you that it can be done, and that the red values are kind of special. Well. For now that is. But please note that I inject this data, but you may not need all changed values. Again, I did this to figure out what we can change, and what not (the red values).

Let’s start with the value 40 You can change this into 30 to get an internel panel. Which is what notebook users want. Also. I cannot change 05 into anything else, without breaking my HDMI monitor – the display turns black. Same thing with 04 because whatever value I use there, then the DVI monitor turns black.

I have no idea why, but it almost looks like Apple/Intel is either using a wrong frame buffer index value – the green bytes – or they are not checking the frame buffer index value at all. I mean my HDMI and DVI monitor are always connected to the first frame buffer, and that is probably also why we can only use one monitor at a time. This also includes remote desktop usage and that sucks, so hopefully this will be fixed soon/tomorrow – or whenever Apple releases (the next) 10.11.3 (DP).

Perhaps this is the workaround that notebook users are looking for, or perhaps they need to swap/change the value (05 and 04). Just give it a try and let me know if this works for you. Thanks.

Note: The Gigabyte B150M-D3H (DDR3) motherboard that we used – thanks Jens – for testing uses port 6 for the DVI and port 5 for the HDMI monitor. By the way. His Geekbench 3 results can be found here and this is the speed of his Samsung SM951 SSD (AHCI).
Samsung SM951 AHCI
Pretty amazing for the Intel i7-6700 (non K) processor.

p.s. Nope. Sorry. The frame buffer edits will not magically “fix” the screen garbage.