⬢ DragonFlyBSD Kernel Audit
DF-5518 / gpoke.c
← back to finding ↓ download raw
/*
 * gpoke.c -- DF-5518 rig helper: plant/read the fake Cherry-View "register"
 * image in the Memory32Fixed window declared by \_SB.GPO0._CRS.
 *
 * Physical window 0x000D0000+0x8000 is ordinary low RAM on this QEMU
 * (4 GB, pc machine).  The window is never excluded from the VM allocator,
 * so the image is planted at runtime (post-boot, as root) via the 64-bit
 * direct map rather than relying on boot-time blob contents surviving.
 *
 * Pin control register layout (gpio_cherryview.c):
 *   PIN_ADDRESS(x) = 0x4400 + (x/15)*0x400 + (x%15)*8
 *   CTL0 @ +0, CTL1 @ +4
 * Plant for all 59 valid chv_n pins (0..8,15..27,30..41,45..56,60..72):
 *   CTL0 = RXSTATE(bit0) on even pins (GPIOCFG=0: passes check_io_pin for
 *          BOTH RX and TX), CTL1 = 0 (INTCFG=0 passes the TX "interrupt
 *          disabled" check).
 * FLD0 (59-bit field over the ascending pin table) then reads the magic
 * pattern computed identically in gen_gpio.py.
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/vmparam.h>

#include <vm/vm_page.h>

#define GPO_BASE	0x000D0000ul
#define CHV_PINS	0x4400
#define PIN_INC		0x400
#define PIN_CHUNK	15

static int chv_n_pins[] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8,
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
	30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
	45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
	60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72
};

#define NCHV	N(chv_n_pins)
#define N(a)	(sizeof(a) / sizeof((a)[0]))

static uint32_t
rd32(vm_paddr_t pa)
{
	return *(volatile uint32_t *)PHYS_TO_DMAP(pa);
}

static void
wr32(vm_paddr_t pa, uint32_t v)
{
	*(volatile uint32_t *)PHYS_TO_DMAP(pa) = v;
}

static vm_paddr_t
pin_ctl0(int pin)
{
	return GPO_BASE + CHV_PINS + (pin / PIN_CHUNK) * PIN_INC +
	    (pin % PIN_CHUNK) * 8;
}

static void
show_pins(const char *tag)
{
	int i;

	kprintf("gpoke[%s]: CTL0 pins (dmap):", tag);
	for (i = 0; i < NCHV; i++)
		kprintf(" %x", rd32(pin_ctl0(chv_n_pins[i])) & 0xFFFF);
	kprintf("\n");
	kprintf("gpoke[%s]: IS=%08x MASK=%08x\n", tag,
	    rd32(GPO_BASE + 0x300), rd32(GPO_BASE + 0x380));
}

static void
show_both(const char *tag)
{
	int i, bad = 0;

	kprintf("gpoke[%s]: pin dmap-vs-kernbase CTL0:", tag);
	for (i = 0; i < NCHV; i++) {
		uint32_t dm = rd32(pin_ctl0(chv_n_pins[i]));
		uint32_t kb = *(volatile uint32_t *)(KERNBASE +
		    pin_ctl0(chv_n_pins[i]));
		if (dm != kb) {
			bad++;
			kprintf(" [p%d dmap=%08x kern=%08x]",
			    chv_n_pins[i], dm, kb);
		}
	}
	kprintf(" (%d differ)\n", bad);
}

static void
plant(void)
{
	int i;

	for (i = 0; i < NCHV; i++) {
		int pin = chv_n_pins[i];

		wr32(pin_ctl0(pin), (pin & 1) ? 0x0 : 0x1);
		wr32(pin_ctl0(pin) + 4, 0x0);
	}
}

static int
gpoke_modevent(module_t mod, int type, void *arg)
{
	switch (type) {
	case MOD_LOAD:
		show_pins("before");
		show_both("before");
		plant();
		show_pins("after");
		show_both("after");
		break;
	case MOD_UNLOAD:
		break;
	default:
		return (EOPNOTSUPP);
	}
	return (0);
}

static moduledata_t gpoke_mod = { "gpoke", gpoke_modevent, NULL };
DECLARE_MODULE(gpoke, gpoke_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_VERSION(gpoke, 1);