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