[BACK]Return to tpm_acpi.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / acpi

File: [cvs.NetBSD.org] / src / sys / dev / acpi / tpm_acpi.c (download)

Revision 1.8.2.2, Wed Aug 3 16:00:47 2022 UTC (20 months, 2 weeks ago) by martin
Branch: netbsd-9
CVS Tags: netbsd-9-3-RELEASE
Changes since 1.8.2.1: +4 -4 lines

Pull up following revision(s) (requested by riastradh in ticket #1495):

	share/man/man4/tpm.4: revision 1.7
	sys/dev/ic/tpm.c: revision 1.17
	sys/dev/ic/tpmvar.h: revision 1.10
	sys/dev/ic/tpm.c: revision 1.18
	sys/dev/ic/tpm.c: revision 1.19
	sys/dev/acpi/tpm_acpi.c: revision 1.14
	sys/dev/ic/tpmreg.h: revision 1.10
	sys/dev/ic/tpmreg.h: revision 1.11
	sys/dev/ic/tpm.c: revision 1.21
	sys/dev/ic/tpm.c: revision 1.22
	sys/dev/ic/tpm.c: revision 1.23
	sys/dev/ic/tpm.c: revision 1.24
	sys/dev/ic/tpm.c: revision 1.25
	sys/dev/ic/tpmreg.h: revision 1.7
	sys/dev/ic/tpmreg.h: revision 1.8
	sys/dev/ic/tpmreg.h: revision 1.9
	sys/dev/ic/tpmvar.h: revision 1.8
	sys/dev/ic/tpmvar.h: revision 1.9

dev/ic/tpm: Tidy up headers.
- Add include guards.
- Add necessary includes.
- Sort includes.
- Use _BYTE_ORDER, not BYTE_ORDER, for public header.

dev/ic/tpm: Add missing line break in attach output.

dev/ic/tpm: Take advantage of entropy source if available.

If the tpm is deactivated, though, detach the entropy source so we
don't continue to try polling it -- it can't be activated without a
reboot anyway.

Add note about enabling TPM and rnd(4) source.

tpm(4): Handle TPM 2.0 random source too, and loop on short reads.
Tested on ThinkPad T480.

tpm(4): Preserve error if any on ending commands.
This way we don't spuriously suppress an error, such as
TPM_DEACTIVATED, in a loop where we rely on it.

tpm@acpi: Require only one locality's worth of register space.
We don't actually use the registers for the other localities, and
some older TPMs only have the first locality exposed via ACPI.


tpm(4): Fix disabling of rnd source if tpm is deactivated.

Nothing prevents a second worker from being queued when the first one
is about to do rnd_detach_source.  Instead, just set a flag so future
requests don't bother running a new thread; if there's a concurrent
one that's already been scheduled on another CPU, well, too bad, we
get a couple extra log messages but that's fine.

A better way to do this would probably be to detect whether the tpm
is deactivated at attach time, but that requires reading more of the
tpm spec than I care to do when there are alternative ways to
procrastinate like scrubbing the toilet.


tpm(4): Fix suspend and rework I/O transaction lock.

Use sc->sc_lock over individual I/O transactions, not open/close of
the whole device.  This way there is a bounded time before the tpm is
unbusied even if userland is getting at it, so userland can't hold up
suspend indefinitely.  Of course, the tpm might be suspended and
resumed in the middle of the user's session this way -- tough.

This limits the response buffer to 1024 bytes -- which is already a
bit hefty to have on the stack (but it's probably not very deep on
the stack from userland so maybe not a big deal).  If it turns out we
need more, we can use kmem to allocate a buffer on the heap, with the
caveat that it might fail.  This is necessary so that suspend doesn't
block indefinitely on uiomove in tpmread.


tpm(4): Nix TPM_BE16/TPM_BE32.  Just use sys/endian.h.

/* $NetBSD: tpm_acpi.c,v 1.8.2.2 2022/08/03 16:00:47 martin Exp $ */

/*
 * Copyright (c) 2012, 2019 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Christos Zoulas and Maxime Villard.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8.2.2 2022/08/03 16:00:47 martin Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/pmf.h>

#include <dev/ic/tpmreg.h>
#include <dev/ic/tpmvar.h>

#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>

#include "ioconf.h"

#define _COMPONENT	ACPI_RESOURCE_COMPONENT
ACPI_MODULE_NAME	("tpm_acpi")

static int	tpm_acpi_match(device_t, cfdata_t, void *);
static void	tpm_acpi_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(tpm_acpi, sizeof(struct tpm_softc), tpm_acpi_match,
    tpm_acpi_attach, NULL, NULL);

/*
 * Supported TPM 2.0 devices.
 */
static const char * const tpm2_acpi_ids[] = {
	"MSFT0101",
	NULL
};

static int
tpm_acpi_match(device_t parent, cfdata_t match, void *aux)
{
	struct acpi_attach_args *aa = aux;
	ACPI_TABLE_TPM2 *tpm2;
	ACPI_STATUS rv;

	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
		return 0;

	/* We support only one TPM. */
	if (tpm_cd.cd_devs && tpm_cd.cd_devs[0])
		return 0;

	if (!acpi_match_hid(aa->aa_node->ad_devinfo, tpm2_acpi_ids))
		return 0;

	/* Make sure it uses TIS, and not CRB. */
	rv = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **)&tpm2);
	if (ACPI_FAILURE(rv))
		return 0;
	if (tpm2->StartMethod != ACPI_TPM2_MEMORY_MAPPED)
		return 0;

	return 1;
}

static void
tpm_acpi_attach(device_t parent, device_t self, void *aux)
{
	struct tpm_softc *sc = device_private(self);
	struct acpi_attach_args *aa = aux;
	struct acpi_resources res;
	struct acpi_mem *mem;
	bus_addr_t base;
	bus_addr_t size;
	int rv;

	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
	    &acpi_resource_parse_ops_default);
	if (ACPI_FAILURE(rv)) {
		aprint_error_dev(self, "cannot parse resources %d\n", rv);
		return;
	}

	mem = acpi_res_mem(&res, 0);
	if (mem == NULL) {
		aprint_error_dev(self, "cannot find mem\n");
		goto out;
	}
	if (mem->ar_length < TPM_SPACE_SIZE) {
		aprint_error_dev(self, "wrong size mem %"PRIu64" < %u\n",
		    (uint64_t)mem->ar_length, TPM_SPACE_SIZE);
		goto out;
	}
	base = mem->ar_base;
	size = mem->ar_length;

	sc->sc_dev = self;
	sc->sc_ver = TPM_2_0;
	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
	sc->sc_busy = false;
	sc->sc_intf = &tpm_intf_tis12;
	sc->sc_bt = aa->aa_memt;
	if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) {
		aprint_error_dev(sc->sc_dev, "cannot map registers\n");
		goto out;
	}

	if ((rv = (*sc->sc_intf->probe)(sc->sc_bt, sc->sc_bh)) != 0) {
		aprint_error_dev(sc->sc_dev, "probe failed, rv=%d\n", rv);
		goto out1;
	}
	if ((rv = (*sc->sc_intf->init)(sc)) != 0) {
		aprint_error_dev(sc->sc_dev, "cannot init device, rv=%d\n", rv);
		goto out1;
	}

	if (!pmf_device_register(self, tpm_suspend, tpm_resume))
		aprint_error_dev(self, "couldn't establish power handler\n");
	acpi_resource_cleanup(&res);
	return;

out1:
	bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
out:
	acpi_resource_cleanup(&res);
}