Skip to content

Instantly share code, notes, and snippets.

@0xbb
Last active December 17, 2022 02:13
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0xbb/974999591da4b1b2635c to your computer and use it in GitHub Desktop.
Save 0xbb/974999591da4b1b2635c to your computer and use it in GitHub Desktop.
Macbook Pro 11,3 - Linux - AppleMuxControl reverse engineering

Macbook Pro 11,3 - Linux gmux

The Macbook Pro 11,3 (late 2013, Retina) is equipped with two GPUs:

  • discrete: NVidia GPU: GeForce GT 750 M
  • integrated: Intel Iris Pro

Currently under Linux the Intel GPU can only be used with the help of:

Otherwise the Intel GPU gets disabled by the EFI.

Steps to access the Intel GPU under Linux:

  • boot Mac OS X
  • start gfxCardStatus v2.2.1
  • select "integrated only" (only needed once)
  • reboot
  • apply "apple_set_os" with a patched grub or patched kernel
  • finally boot Linux

Reverse Engineering

To improve this situation reverse engineering of Apple's switching driver is attempted and documented here.

Observations:

  • gfxCardStatus basically only calls Apple's GPU swichting driver
  • the "integrated only" settings is persistent

So it seems logical that the GPU selection is stored in some NVRAM / EFI variable.

Analysis of AppleMuxControl

/System/Library/Extensions/AppleGraphicsControl.kext/Contents/Plugins/AppleMuxControl.kext is responsible for switching GPUs and saving of the current state.

So AppleMuxControl was disassembled and the following EFI GUID + variable were found:

fa4ce28d-b62f-4c99-9cc3-6815686e30f9 + gpu-power-prefs

This variable also shows up in efivarfs in Linux when the Nvidia GPU is activated. The attempt of reading this variable fails with an IO error.

gpu-power-prefs seems to be protected from access maybe, because of a not set the EFI_VARIABLE_RUNTIME_ACCESS attribute.

EFI based variable reading

With this knowledge further attempts to read this var were started. A EFI program based on https://github.com/android-ia/platform_external_efitools/ - ReadVars.c was develop.

It can be started via a EFI Shell and can read out EFI variables. Currently it also fails to read out gpu-power-prfes with EFI_ACCESS_DENIED.

Next Up

Further tries to read out gpu-power-prefs and analysis.

Any input or feedback are welcome!


References:

/*
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
*
* see COPYING file
*
* Read and dump all the secure variables
*/
#include <efi.h>
#include <efilib.h>
#include <simple_file.h>
#include <guid.h>
#include <variables.h>
#include <shell.h>
#include <x509.h>
#include <sha256.h>
#include "efiauthenticated.h"
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
EFI_STATUS status;
CHAR16 *variables[] = {L"gpu-policy", L"gpu-power-prefs", L"gpu-power-prefs"};
// gpu-power-prefs - GUID
EFI_GUID guid_prefs = { 0xfa4ce28d, 0xb62f, 0x4c99, {0x9c, 0xc3, 0x68, 0x15, 0x68, 0x6e, 0x30, 0xf9}};
// gpu-policy - GUID
EFI_GUID guid_policy = { 0x7c436110, 0xab2a, 0x4bbb, {0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82}};
// set the 1st GUID wrong to see if there is a different error
EFI_GUID owners[] = { guid_policy, guid_policy, guid_prefs};
CHAR16 **ARGV, *progname;
UINT8 *data;
UINTN len;
int i, argc, save_keys = 0, no_print = 0;
InitializeLib(image, systab);
status = argsplit(image, &argc, &ARGV);
if (status != EFI_SUCCESS) {
Print(L"Failed to parse arguments: %d\n", status);
return status;
}
for (i = 0; i < ARRAY_SIZE(owners); i++) {
status = get_variable(variables[i], &data, &len, owners[i]);
if (status == EFI_NOT_FOUND) {
Print(L"Variable %s has no entries\n", variables[i]);
} else if (status != EFI_SUCCESS) {
Print(L"Failed to get %s: %d\n", variables[i], status);
} else {
Print(L"Variable %s length %d\n", variables[i], len, *data);
FreePool(data);
}
}
return EFI_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment