Patrick Rudolph | d8d8be1 | 2020-09-21 09:48:53 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <types.h> |
Patrick Rudolph | d8d8be1 | 2020-09-21 09:48:53 +0200 | [diff] [blame] | 4 | #include <acpi/acpi.h> |
| 5 | #include <acpi/acpigen.h> |
| 6 | #include <acpi/acpi_device.h> |
| 7 | |
| 8 | #include "tpm_ppi.h" |
| 9 | |
| 10 | static void tpm_ppi_func0_cb(void *arg) |
| 11 | { |
| 12 | /* Functions 1-8. */ |
| 13 | u8 buf[] = {0xff, 0x01}; |
| 14 | acpigen_write_return_byte_buffer(buf, sizeof(buf)); |
| 15 | } |
| 16 | |
| 17 | static void tpm_ppi_func1_cb(void *arg) |
| 18 | { |
| 19 | if (CONFIG(TPM2)) |
Patrick Rudolph | 2bea58d | 2020-09-21 10:27:40 +0200 | [diff] [blame] | 20 | /* Interface version: 1.3 */ |
| 21 | acpigen_write_return_string("1.3"); |
Patrick Rudolph | d8d8be1 | 2020-09-21 09:48:53 +0200 | [diff] [blame] | 22 | else |
| 23 | /* Interface version: 1.2 */ |
| 24 | acpigen_write_return_string("1.2"); |
| 25 | } |
| 26 | |
| 27 | static void tpm_ppi_func2_cb(void *arg) |
| 28 | { |
| 29 | /* Submit operations: drop on the floor and return success. */ |
| 30 | acpigen_write_return_byte(PPI2_RET_SUCCESS); |
| 31 | } |
| 32 | |
| 33 | static void tpm_ppi_func3_cb(void *arg) |
| 34 | { |
| 35 | /* Pending operation: none. */ |
| 36 | acpigen_emit_byte(RETURN_OP); |
| 37 | acpigen_write_package(2); |
| 38 | acpigen_write_byte(0); |
| 39 | acpigen_write_byte(0); |
| 40 | acpigen_pop_len(); |
| 41 | } |
| 42 | |
| 43 | static void tpm_ppi_func4_cb(void *arg) |
| 44 | { |
| 45 | /* Pre-OS transition method: reboot. */ |
| 46 | acpigen_write_return_byte(2); |
| 47 | } |
| 48 | |
| 49 | static void tpm_ppi_func5_cb(void *arg) |
| 50 | { |
| 51 | /* Operation response: no operation executed. */ |
| 52 | acpigen_emit_byte(RETURN_OP); |
| 53 | acpigen_write_package(3); |
| 54 | acpigen_write_byte(0); |
| 55 | acpigen_write_byte(0); |
| 56 | acpigen_write_byte(0); |
| 57 | acpigen_pop_len(); |
| 58 | } |
| 59 | |
| 60 | static void tpm_ppi_func6_cb(void *arg) |
| 61 | { |
| 62 | /* |
| 63 | * Set preferred user language: deprecated and must return 3 AKA |
| 64 | * "not implemented". |
| 65 | */ |
| 66 | acpigen_write_return_byte(PPI6_RET_NOT_IMPLEMENTED); |
| 67 | } |
| 68 | |
| 69 | static void tpm_ppi_func7_cb(void *arg) |
| 70 | { |
| 71 | /* Submit operations: deny. */ |
| 72 | acpigen_write_return_byte(PPI7_RET_BLOCKED_BY_FIRMWARE); |
| 73 | } |
| 74 | |
| 75 | static void tpm_ppi_func8_cb(void *arg) |
| 76 | { |
| 77 | /* All actions are forbidden. */ |
| 78 | acpigen_write_return_byte(PPI8_RET_FIRMWARE_ONLY); |
| 79 | } |
| 80 | |
| 81 | static void (*tpm_ppi_callbacks[])(void *) = { |
| 82 | tpm_ppi_func0_cb, |
| 83 | tpm_ppi_func1_cb, |
| 84 | tpm_ppi_func2_cb, |
| 85 | tpm_ppi_func3_cb, |
| 86 | tpm_ppi_func4_cb, |
| 87 | tpm_ppi_func5_cb, |
| 88 | tpm_ppi_func6_cb, |
| 89 | tpm_ppi_func7_cb, |
| 90 | tpm_ppi_func8_cb, |
| 91 | }; |
| 92 | |
| 93 | static void tpm_mci_func0_cb(void *arg) |
| 94 | { |
| 95 | /* Function 1. */ |
| 96 | acpigen_write_return_singleton_buffer(0x3); |
| 97 | } |
| 98 | static void tpm_mci_func1_cb(void *arg) |
| 99 | { |
| 100 | /* Just return success. */ |
| 101 | acpigen_write_return_byte(0); |
| 102 | } |
| 103 | |
| 104 | static void (*tpm_mci_callbacks[])(void *) = { |
| 105 | tpm_mci_func0_cb, |
| 106 | tpm_mci_func1_cb, |
| 107 | }; |
| 108 | |
| 109 | void tpm_ppi_acpi_fill_ssdt(const struct device *dev) |
| 110 | { |
| 111 | /* |
| 112 | * _DSM method |
| 113 | */ |
| 114 | struct dsm_uuid ids[] = { |
| 115 | /* Physical presence interface. |
| 116 | * This is used to submit commands like "Clear TPM" to |
| 117 | * be run at next reboot provided that user confirms |
| 118 | * them. Spec allows user to cancel all commands and/or |
| 119 | * configure BIOS to reject commands. So we pretend that |
| 120 | * user did just this: cancelled everything. If user |
| 121 | * really wants to clear TPM the only option now is to |
| 122 | * do it manually in payload. |
| 123 | */ |
| 124 | DSM_UUID(TPM_PPI_UUID, tpm_ppi_callbacks, |
| 125 | ARRAY_SIZE(tpm_ppi_callbacks), NULL), |
| 126 | /* Memory clearing on boot: just a dummy. */ |
| 127 | DSM_UUID(TPM_MCI_UUID, tpm_mci_callbacks, |
| 128 | ARRAY_SIZE(tpm_mci_callbacks), NULL), |
| 129 | }; |
| 130 | |
| 131 | acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids)); |
| 132 | } |