aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/tpm/ppi_stub.c
blob: 11bd07e10abe31190eb7655046d1924c24b37e26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* SPDX-License-Identifier: GPL-2.0-only */

#include <types.h>
#include <stddef.h>
#include <acpi/acpi.h>
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>

#include "tpm_ppi.h"

static void tpm_ppi_func0_cb(void *arg)
{
	/* Functions 1-8. */
	u8 buf[] = {0xff, 0x01};
	acpigen_write_return_byte_buffer(buf, sizeof(buf));
}

static void tpm_ppi_func1_cb(void *arg)
{
	if (CONFIG(TPM2))
		/* Interface version: 2.0 */
		acpigen_write_return_string("2.0");
	else
		/* Interface version: 1.2 */
		acpigen_write_return_string("1.2");
}

static void tpm_ppi_func2_cb(void *arg)
{
	/* Submit operations: drop on the floor and return success. */
	acpigen_write_return_byte(PPI2_RET_SUCCESS);
}

static void tpm_ppi_func3_cb(void *arg)
{
	/* Pending operation: none. */
	acpigen_emit_byte(RETURN_OP);
	acpigen_write_package(2);
	acpigen_write_byte(0);
	acpigen_write_byte(0);
	acpigen_pop_len();
}

static void tpm_ppi_func4_cb(void *arg)
{
	/* Pre-OS transition method: reboot. */
	acpigen_write_return_byte(2);
}

static void tpm_ppi_func5_cb(void *arg)
{
	/* Operation response: no operation executed. */
	acpigen_emit_byte(RETURN_OP);
	acpigen_write_package(3);
	acpigen_write_byte(0);
	acpigen_write_byte(0);
	acpigen_write_byte(0);
	acpigen_pop_len();
}

static void tpm_ppi_func6_cb(void *arg)
{
	/*
	 * Set preferred user language: deprecated and must return 3 AKA
	 * "not implemented".
	 */
	acpigen_write_return_byte(PPI6_RET_NOT_IMPLEMENTED);
}

static void tpm_ppi_func7_cb(void *arg)
{
	/* Submit operations: deny. */
	acpigen_write_return_byte(PPI7_RET_BLOCKED_BY_FIRMWARE);
}

static void tpm_ppi_func8_cb(void *arg)
{
	/* All actions are forbidden. */
	acpigen_write_return_byte(PPI8_RET_FIRMWARE_ONLY);
}

static void (*tpm_ppi_callbacks[])(void *) = {
	tpm_ppi_func0_cb,
	tpm_ppi_func1_cb,
	tpm_ppi_func2_cb,
	tpm_ppi_func3_cb,
	tpm_ppi_func4_cb,
	tpm_ppi_func5_cb,
	tpm_ppi_func6_cb,
	tpm_ppi_func7_cb,
	tpm_ppi_func8_cb,
};

static void tpm_mci_func0_cb(void *arg)
{
	/* Function 1. */
	acpigen_write_return_singleton_buffer(0x3);
}
static void tpm_mci_func1_cb(void *arg)
{
	/* Just return success. */
	acpigen_write_return_byte(0);
}

static void (*tpm_mci_callbacks[])(void *) = {
	tpm_mci_func0_cb,
	tpm_mci_func1_cb,
};

void tpm_ppi_acpi_fill_ssdt(const struct device *dev)
{
	/*
	 * _DSM method
	 */
	struct dsm_uuid ids[] = {
		/* Physical presence interface.
		 * This is used to submit commands like "Clear TPM" to
		 * be run at next reboot provided that user confirms
		 * them. Spec allows user to cancel all commands and/or
		 * configure BIOS to reject commands. So we pretend that
		 * user did just this: cancelled everything. If user
		 * really wants to clear TPM the only option now is to
		 * do it manually in payload.
		 */
		DSM_UUID(TPM_PPI_UUID, tpm_ppi_callbacks,
			ARRAY_SIZE(tpm_ppi_callbacks), NULL),
		/* Memory clearing on boot: just a dummy. */
		DSM_UUID(TPM_MCI_UUID, tpm_mci_callbacks,
			ARRAY_SIZE(tpm_mci_callbacks), NULL),
	};

	acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids));
}