⬢ DragonFlyBSD Kernel Audit
sys/dev/apple/fw/apple_fw.c
← back
/*
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2026 Abdelkader Boudih <dragonflybsd@seuros.com>
 *
 * Apple EFI Firmware Properties driver for DragonFly BSD.
 *
 * Discovers Apple-specific ACPI structures on Macs:
 * - Enumerates Apple SSDTs (SmcDppt, PcieTbt, Sdxc, etc.)
 * - Evaluates OSDW (macOS detection flag)
 * - Walks namespace for _DSM methods using Apple's DTGP UUID
 * - Extracts device properties and exposes via sysctl
 */

#include "apple_fw.h"
#include <contrib/dev/acpica/source/include/acnamesp.h>

#define _COMPONENT	ACPI_OEM
ACPI_MODULE_NAME("APPLE_FW")

MALLOC_DEFINE(M_APPLEFW, "apple_fw", "Apple EFI firmware driver");

static int	apple_fw_identify(driver_t *, device_t);
static int	apple_fw_probe(device_t);
static int	apple_fw_attach(device_t);
static int	apple_fw_detach(device_t);

static void	apple_fw_enumerate_ssdts(device_t);
static void	apple_fw_eval_osdw(device_t);
static void	apple_fw_fixup_osys(device_t);

static device_method_t apple_fw_methods[] = {
	DEVMETHOD(device_identify,	apple_fw_identify),
	DEVMETHOD(device_probe,		apple_fw_probe),
	DEVMETHOD(device_attach,	apple_fw_attach),
	DEVMETHOD(device_detach,	apple_fw_detach),
	DEVMETHOD_END
};

static driver_t apple_fw_driver = {
	"apple_fw",
	apple_fw_methods,
	sizeof(struct apple_fw_softc),
	.gpri = KOBJ_GPRI_ACPI
};

static devclass_t apple_fw_devclass;

DRIVER_MODULE(apple_fw, acpi, apple_fw_driver, apple_fw_devclass,
    NULL, NULL);
MODULE_DEPEND(apple_fw, acpi, 1, 1, 1);
MODULE_VERSION(apple_fw, 1);

/*
 * Check if running on Apple EFI firmware by examining the FADT OEM ID.
 */
static int
apple_fw_is_apple(void)
{
	ACPI_TABLE_HEADER hdr;
	ACPI_STATUS status;

	status = AcpiGetTableHeader(ACPI_SIG_FADT, 0, &hdr);
	if (ACPI_FAILURE(status))
		return (0);
	return (strncmp(hdr.OemId, "APPLE ", ACPI_OEM_ID_SIZE) == 0);
}

/*
 * Tag value for our synthetic child -- used by probe to distinguish
 * the device we create from real ACPI-enumerated devices.
 */
#define	DEV_APPLE_FW(x)	\
    (acpi_get_magic(x) == (uintptr_t)&apple_fw_devclass)

static int
apple_fw_identify(driver_t *driver, device_t parent)
{
	device_t child;

	/* Don't re-add on bus rescan */
	if (device_find_child(parent, "apple_fw", -1) != NULL)
		return (0);

	if (!apple_fw_is_apple())
		return (ENXIO);

	child = BUS_ADD_CHILD(parent, parent, 0, "apple_fw", -1);
	if (child != NULL)
		acpi_set_magic(child, (uintptr_t)&apple_fw_devclass);
	return (0);
}

static int
apple_fw_probe(device_t dev)
{
	char *product, *biosver;
	char desc[128];

	if (acpi_disabled("apple_fw"))
		return (ENXIO);

	/* Only match the synthetic child we tagged in identify */
	if (!DEV_APPLE_FW(dev))
		return (ENXIO);

	product = kgetenv("smbios.system.product");
	biosver = kgetenv("smbios.bios.version");
	ksnprintf(desc, sizeof(desc), "Apple %s EFI Firmware %s",
	    product, biosver);
	device_set_desc_copy(dev, desc);
	kfreeenv(product);
	kfreeenv(biosver);

	return (0);
}

static int
apple_fw_attach(device_t dev)
{
	struct apple_fw_softc *sc = device_get_softc(dev);
	int darwin_osi = 1;

	sc->sc_dev = dev;
	lockinit(&sc->sc_lock, "apple_fw", 0, LK_CANRECURSE);

	/* Enumerate Apple-specific SSDTs */
	apple_fw_enumerate_ssdts(dev);

	/*
	 * If the Darwin OSI tunable is enabled but the early path
	 * didn't run (module loaded late), fix up OSYS ourselves.
	 * If the tunable is disabled, the user opted out -- skip.
	 */
	TUNABLE_INT_FETCH("hw.acpi.apple_darwin_osi", &darwin_osi);
	apple_fw_eval_osdw(dev);
	if (darwin_osi && sc->sc_osdw == 0)
		apple_fw_fixup_osys(dev);

	/* Discover _DSM device properties via DTGP */
	apple_fw_discover_dsm_devices(dev);

	/* Register sysctl tree */
	apple_fw_sysctl_init(dev);

	return (0);
}

static int
apple_fw_detach(device_t dev)
{
	struct apple_fw_softc *sc = device_get_softc(dev);

	lockuninit(&sc->sc_lock);
	return (0);
}

/*
 * Fix up OSYS when Darwin OSI was not installed before AcpiLoadTables.
 *
 * Install the Darwin interface (affects future _OSI queries), then
 * re-evaluate PINI which re-checks _OSI and sets OSYS=0x2710.
 * If PINI is not present, write OSYS directly via the namespace.
 */
#define APPLE_OSYS_DARWIN	0x2710

static void
apple_fw_fixup_osys(device_t dev)
{
	struct apple_fw_softc *sc = device_get_softc(dev);
	ACPI_STATUS status;

	/* Install Darwin so future _OSI("Darwin") calls return true */
	AcpiInstallInterface("Darwin");

	/* Try re-evaluating PINI (Apple's _OSI->OSYS dispatcher) */
	status = AcpiEvaluateObject(NULL, "\\PINI", NULL, NULL);
	if (ACPI_SUCCESS(status)) {
		apple_fw_eval_osdw(dev);
		if (sc->sc_osdw != 0) {
			device_printf(dev, "Darwin OSI fixup via PINI\n");
			return;
		}
	}

	/* PINI missing or didn't help -- write OSYS directly */
	{
		ACPI_HANDLE handle;
		ACPI_NAMESPACE_NODE *node;
		ACPI_OPERAND_OBJECT *obj;

		status = AcpiGetHandle(NULL, "\\OSYS", &handle);
		if (ACPI_FAILURE(status)) {
			device_printf(dev,
			    "Darwin OSI fixup failed: no \\OSYS\n");
			return;
		}

		node = AcpiNsValidateHandle(handle);
		if (node == NULL)
			return;

		obj = AcpiNsGetAttachedObject(node);
		if (obj != NULL &&
		    obj->Common.Type == ACPI_TYPE_INTEGER) {
			obj->Integer.Value = APPLE_OSYS_DARWIN;
			apple_fw_eval_osdw(dev);
			device_printf(dev,
			    "Darwin OSI fixup via OSYS poke\n");
		}
	}
}

/*
 * Enumerate all SSDT tables with OEM ID "APPLE".
 */
static void
apple_fw_enumerate_ssdts(device_t dev)
{
	struct apple_fw_softc *sc = device_get_softc(dev);
	ACPI_TABLE_HEADER *table;
	ACPI_STATUS status;
	uint32_t instance;
	int n;

	sc->sc_ssdt_count = 0;

	for (instance = 1; instance <= 128; instance++) {
		status = AcpiGetTable(ACPI_SIG_SSDT, instance, &table);
		if (ACPI_FAILURE(status))
			break;

		/* Only catalog Apple SSDTs */
		if (strncmp(table->OemId, "APPLE ", ACPI_OEM_ID_SIZE) != 0)
			continue;

		n = sc->sc_ssdt_count;
		if (n >= APPLE_FW_MAX_SSDTS)
			break;

		memcpy(sc->sc_ssdts[n].oem_table_id, table->OemTableId,
		    ACPI_OEM_TABLE_ID_SIZE);
		sc->sc_ssdts[n].oem_table_id[ACPI_OEM_TABLE_ID_SIZE] = '\0';
		sc->sc_ssdt_count++;
	}
}

/*
 * Evaluate the OSDW method.  Returns 1 if the firmware thinks macOS is
 * running (OSYS == 0x2710), 0 otherwise.
 */
static void
apple_fw_eval_osdw(device_t dev)
{
	struct apple_fw_softc *sc = device_get_softc(dev);
	UINT32 val;

	sc->sc_osdw = 0;

	if (ACPI_SUCCESS(acpi_GetInteger(NULL, "OSDW", &val)))
		sc->sc_osdw = (int)val;
}