1f84fdff0SXiaoyan Zhang #include <linux/acpi.h> 2f84fdff0SXiaoyan Zhang #include <acpi/acpi_drivers.h> 3f84fdff0SXiaoyan Zhang #include "tpm.h" 4f84fdff0SXiaoyan Zhang 5f84fdff0SXiaoyan Zhang static const u8 tpm_ppi_uuid[] = { 6f84fdff0SXiaoyan Zhang 0xA6, 0xFA, 0xDD, 0x3D, 7f84fdff0SXiaoyan Zhang 0x1B, 0x36, 8f84fdff0SXiaoyan Zhang 0xB4, 0x4E, 9f84fdff0SXiaoyan Zhang 0xA4, 0x24, 10f84fdff0SXiaoyan Zhang 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 11f84fdff0SXiaoyan Zhang }; 12f84fdff0SXiaoyan Zhang static char *tpm_device_name = "TPM"; 13f84fdff0SXiaoyan Zhang 14f84fdff0SXiaoyan Zhang #define TPM_PPI_REVISION_ID 1 15f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_VERSION 1 16f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_SUBREQ 2 17f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETREQ 3 18f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETACT 4 19f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETRSP 5 20f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_SUBREQ2 7 21f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETOPR 8 22f84fdff0SXiaoyan Zhang #define PPI_TPM_REQ_MAX 22 23f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_START 128 24f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_END 255 25f84fdff0SXiaoyan Zhang #define PPI_VERSION_LEN 3 26f84fdff0SXiaoyan Zhang 27f84fdff0SXiaoyan Zhang static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, 28f84fdff0SXiaoyan Zhang void **return_value) 29f84fdff0SXiaoyan Zhang { 30f84fdff0SXiaoyan Zhang acpi_status status; 31f84fdff0SXiaoyan Zhang struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 32f84fdff0SXiaoyan Zhang status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 33f84fdff0SXiaoyan Zhang if (strstr(buffer.pointer, context) != NULL) { 34f84fdff0SXiaoyan Zhang *return_value = handle; 35f84fdff0SXiaoyan Zhang kfree(buffer.pointer); 36f84fdff0SXiaoyan Zhang return AE_CTRL_TERMINATE; 37f84fdff0SXiaoyan Zhang } 38f84fdff0SXiaoyan Zhang return AE_OK; 39f84fdff0SXiaoyan Zhang } 40f84fdff0SXiaoyan Zhang 41f84fdff0SXiaoyan Zhang static inline void ppi_assign_params(union acpi_object params[4], 42f84fdff0SXiaoyan Zhang u64 function_num) 43f84fdff0SXiaoyan Zhang { 44f84fdff0SXiaoyan Zhang params[0].type = ACPI_TYPE_BUFFER; 45f84fdff0SXiaoyan Zhang params[0].buffer.length = sizeof(tpm_ppi_uuid); 46f84fdff0SXiaoyan Zhang params[0].buffer.pointer = (char *)tpm_ppi_uuid; 47f84fdff0SXiaoyan Zhang params[1].type = ACPI_TYPE_INTEGER; 48f84fdff0SXiaoyan Zhang params[1].integer.value = TPM_PPI_REVISION_ID; 49f84fdff0SXiaoyan Zhang params[2].type = ACPI_TYPE_INTEGER; 50f84fdff0SXiaoyan Zhang params[2].integer.value = function_num; 51f84fdff0SXiaoyan Zhang params[3].type = ACPI_TYPE_PACKAGE; 52f84fdff0SXiaoyan Zhang params[3].package.count = 0; 53f84fdff0SXiaoyan Zhang params[3].package.elements = NULL; 54f84fdff0SXiaoyan Zhang } 55f84fdff0SXiaoyan Zhang 5681198078SXiaoyan Zhang static ssize_t tpm_show_ppi_version(struct device *dev, 5781198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 58f84fdff0SXiaoyan Zhang { 59f84fdff0SXiaoyan Zhang acpi_handle handle; 60f84fdff0SXiaoyan Zhang acpi_status status; 61f84fdff0SXiaoyan Zhang struct acpi_object_list input; 62f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 63f84fdff0SXiaoyan Zhang union acpi_object params[4]; 64f84fdff0SXiaoyan Zhang union acpi_object *obj; 65f84fdff0SXiaoyan Zhang 66f84fdff0SXiaoyan Zhang input.count = 4; 67f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_VERSION); 68f84fdff0SXiaoyan Zhang input.pointer = params; 69f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 70f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 71f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 72f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 73f84fdff0SXiaoyan Zhang return -ENXIO; 74f84fdff0SXiaoyan Zhang 75f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 76f84fdff0SXiaoyan Zhang ACPI_TYPE_STRING); 77f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 78f84fdff0SXiaoyan Zhang return -ENOMEM; 79f84fdff0SXiaoyan Zhang obj = (union acpi_object *)output.pointer; 80f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); 81f84fdff0SXiaoyan Zhang kfree(output.pointer); 82f84fdff0SXiaoyan Zhang return status; 83f84fdff0SXiaoyan Zhang } 84f84fdff0SXiaoyan Zhang 8581198078SXiaoyan Zhang static ssize_t tpm_show_ppi_request(struct device *dev, 8681198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 87f84fdff0SXiaoyan Zhang { 88f84fdff0SXiaoyan Zhang acpi_handle handle; 89f84fdff0SXiaoyan Zhang acpi_status status; 90f84fdff0SXiaoyan Zhang struct acpi_object_list input; 91f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 92f84fdff0SXiaoyan Zhang union acpi_object params[4]; 93f84fdff0SXiaoyan Zhang union acpi_object *ret_obj; 94f84fdff0SXiaoyan Zhang 95f84fdff0SXiaoyan Zhang input.count = 4; 96f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_GETREQ); 97f84fdff0SXiaoyan Zhang input.pointer = params; 98f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 99f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 100f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 101f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 102f84fdff0SXiaoyan Zhang return -ENXIO; 103f84fdff0SXiaoyan Zhang 104f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 105f84fdff0SXiaoyan Zhang ACPI_TYPE_PACKAGE); 106f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 107f84fdff0SXiaoyan Zhang return -ENOMEM; 108f84fdff0SXiaoyan Zhang /* 109f84fdff0SXiaoyan Zhang * output.pointer should be of package type, including two integers. 110f84fdff0SXiaoyan Zhang * The first is function return code, 0 means success and 1 means 111f84fdff0SXiaoyan Zhang * error. The second is pending TPM operation requested by the OS, 0 112f84fdff0SXiaoyan Zhang * means none and >0 means operation value. 113f84fdff0SXiaoyan Zhang */ 114f84fdff0SXiaoyan Zhang ret_obj = ((union acpi_object *)output.pointer)->package.elements; 115f84fdff0SXiaoyan Zhang if (ret_obj->type == ACPI_TYPE_INTEGER) { 116f84fdff0SXiaoyan Zhang if (ret_obj->integer.value) { 117f84fdff0SXiaoyan Zhang status = -EFAULT; 118f84fdff0SXiaoyan Zhang goto cleanup; 119f84fdff0SXiaoyan Zhang } 120f84fdff0SXiaoyan Zhang ret_obj++; 121f84fdff0SXiaoyan Zhang if (ret_obj->type == ACPI_TYPE_INTEGER) 122f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu\n", 123f84fdff0SXiaoyan Zhang ret_obj->integer.value); 124f84fdff0SXiaoyan Zhang else 125f84fdff0SXiaoyan Zhang status = -EINVAL; 126f84fdff0SXiaoyan Zhang } else { 127f84fdff0SXiaoyan Zhang status = -EINVAL; 128f84fdff0SXiaoyan Zhang } 129f84fdff0SXiaoyan Zhang cleanup: 130f84fdff0SXiaoyan Zhang kfree(output.pointer); 131f84fdff0SXiaoyan Zhang return status; 132f84fdff0SXiaoyan Zhang } 133f84fdff0SXiaoyan Zhang 13481198078SXiaoyan Zhang static ssize_t tpm_store_ppi_request(struct device *dev, 135f84fdff0SXiaoyan Zhang struct device_attribute *attr, 136f84fdff0SXiaoyan Zhang const char *buf, size_t count) 137f84fdff0SXiaoyan Zhang { 138f84fdff0SXiaoyan Zhang char version[PPI_VERSION_LEN + 1]; 139f84fdff0SXiaoyan Zhang acpi_handle handle; 140f84fdff0SXiaoyan Zhang acpi_status status; 141f84fdff0SXiaoyan Zhang struct acpi_object_list input; 142f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 143f84fdff0SXiaoyan Zhang union acpi_object params[4]; 144f84fdff0SXiaoyan Zhang union acpi_object obj; 145f84fdff0SXiaoyan Zhang u32 req; 146f84fdff0SXiaoyan Zhang u64 ret; 147f84fdff0SXiaoyan Zhang 148f84fdff0SXiaoyan Zhang input.count = 4; 149f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_VERSION); 150f84fdff0SXiaoyan Zhang input.pointer = params; 151f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 152f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 153f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 154f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 155f84fdff0SXiaoyan Zhang return -ENXIO; 156f84fdff0SXiaoyan Zhang 157f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 158f84fdff0SXiaoyan Zhang ACPI_TYPE_STRING); 159f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 160f84fdff0SXiaoyan Zhang return -ENOMEM; 161f84fdff0SXiaoyan Zhang strncpy(version, 162f84fdff0SXiaoyan Zhang ((union acpi_object *)output.pointer)->string.pointer, 163f84fdff0SXiaoyan Zhang PPI_VERSION_LEN); 164f84fdff0SXiaoyan Zhang kfree(output.pointer); 165f84fdff0SXiaoyan Zhang output.length = ACPI_ALLOCATE_BUFFER; 166f84fdff0SXiaoyan Zhang output.pointer = NULL; 167f84fdff0SXiaoyan Zhang /* 168f84fdff0SXiaoyan Zhang * the function to submit TPM operation request to pre-os environment 169f84fdff0SXiaoyan Zhang * is updated with function index from SUBREQ to SUBREQ2 since PPI 170f84fdff0SXiaoyan Zhang * version 1.1 171f84fdff0SXiaoyan Zhang */ 172f84fdff0SXiaoyan Zhang if (strcmp(version, "1.1") == -1) 173f84fdff0SXiaoyan Zhang params[2].integer.value = TPM_PPI_FN_SUBREQ; 174f84fdff0SXiaoyan Zhang else 175f84fdff0SXiaoyan Zhang params[2].integer.value = TPM_PPI_FN_SUBREQ2; 176f84fdff0SXiaoyan Zhang /* 177f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 178f84fdff0SXiaoyan Zhang * accept buffer/string/integer type, but some BIOS accept buffer/ 179f84fdff0SXiaoyan Zhang * string/package type. For PPI version 1.0 and 1.1, use buffer type 180f84fdff0SXiaoyan Zhang * for compatibility, and use package type since 1.2 according to spec. 181f84fdff0SXiaoyan Zhang */ 182f84fdff0SXiaoyan Zhang if (strcmp(version, "1.2") == -1) { 183f84fdff0SXiaoyan Zhang params[3].type = ACPI_TYPE_BUFFER; 184f84fdff0SXiaoyan Zhang params[3].buffer.length = sizeof(req); 185f84fdff0SXiaoyan Zhang sscanf(buf, "%d", &req); 186f84fdff0SXiaoyan Zhang params[3].buffer.pointer = (char *)&req; 187f84fdff0SXiaoyan Zhang } else { 188f84fdff0SXiaoyan Zhang params[3].package.count = 1; 189f84fdff0SXiaoyan Zhang obj.type = ACPI_TYPE_INTEGER; 190f84fdff0SXiaoyan Zhang sscanf(buf, "%llu", &obj.integer.value); 191f84fdff0SXiaoyan Zhang params[3].package.elements = &obj; 192f84fdff0SXiaoyan Zhang } 193f84fdff0SXiaoyan Zhang 194f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 195f84fdff0SXiaoyan Zhang ACPI_TYPE_INTEGER); 196f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 197f84fdff0SXiaoyan Zhang return -ENOMEM; 198f84fdff0SXiaoyan Zhang ret = ((union acpi_object *)output.pointer)->integer.value; 199f84fdff0SXiaoyan Zhang if (ret == 0) 200f84fdff0SXiaoyan Zhang status = (acpi_status)count; 201f84fdff0SXiaoyan Zhang else if (ret == 1) 202f84fdff0SXiaoyan Zhang status = -EPERM; 203f84fdff0SXiaoyan Zhang else 204f84fdff0SXiaoyan Zhang status = -EFAULT; 205f84fdff0SXiaoyan Zhang kfree(output.pointer); 206f84fdff0SXiaoyan Zhang return status; 207f84fdff0SXiaoyan Zhang } 208f84fdff0SXiaoyan Zhang 20981198078SXiaoyan Zhang static ssize_t tpm_show_ppi_transition_action(struct device *dev, 210f84fdff0SXiaoyan Zhang struct device_attribute *attr, 211f84fdff0SXiaoyan Zhang char *buf) 212f84fdff0SXiaoyan Zhang { 213f84fdff0SXiaoyan Zhang char version[PPI_VERSION_LEN + 1]; 214f84fdff0SXiaoyan Zhang acpi_handle handle; 215f84fdff0SXiaoyan Zhang acpi_status status; 216f84fdff0SXiaoyan Zhang struct acpi_object_list input; 217f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 218f84fdff0SXiaoyan Zhang union acpi_object params[4]; 219f84fdff0SXiaoyan Zhang u32 ret; 220f84fdff0SXiaoyan Zhang char *info[] = { 221f84fdff0SXiaoyan Zhang "None", 222f84fdff0SXiaoyan Zhang "Shutdown", 223f84fdff0SXiaoyan Zhang "Reboot", 224f84fdff0SXiaoyan Zhang "OS Vendor-specific", 225f84fdff0SXiaoyan Zhang "Error", 226f84fdff0SXiaoyan Zhang }; 227f84fdff0SXiaoyan Zhang input.count = 4; 228f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_VERSION); 229f84fdff0SXiaoyan Zhang input.pointer = params; 230f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 231f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 232f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 233f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 234f84fdff0SXiaoyan Zhang return -ENXIO; 235f84fdff0SXiaoyan Zhang 236f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 237f84fdff0SXiaoyan Zhang ACPI_TYPE_STRING); 238f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 239f84fdff0SXiaoyan Zhang return -ENOMEM; 240f84fdff0SXiaoyan Zhang strncpy(version, 241f84fdff0SXiaoyan Zhang ((union acpi_object *)output.pointer)->string.pointer, 242f84fdff0SXiaoyan Zhang PPI_VERSION_LEN); 243f84fdff0SXiaoyan Zhang /* 244f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as empty package, but some platforms 245f84fdff0SXiaoyan Zhang * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 246f84fdff0SXiaoyan Zhang * compatibility, define params[3].type as buffer, if PPI version < 1.2 247f84fdff0SXiaoyan Zhang */ 248f84fdff0SXiaoyan Zhang if (strcmp(version, "1.2") == -1) { 249f84fdff0SXiaoyan Zhang params[3].type = ACPI_TYPE_BUFFER; 250f84fdff0SXiaoyan Zhang params[3].buffer.length = 0; 251f84fdff0SXiaoyan Zhang params[3].buffer.pointer = NULL; 252f84fdff0SXiaoyan Zhang } 253f84fdff0SXiaoyan Zhang params[2].integer.value = TPM_PPI_FN_GETACT; 254f84fdff0SXiaoyan Zhang kfree(output.pointer); 255f84fdff0SXiaoyan Zhang output.length = ACPI_ALLOCATE_BUFFER; 256f84fdff0SXiaoyan Zhang output.pointer = NULL; 257f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 258f84fdff0SXiaoyan Zhang ACPI_TYPE_INTEGER); 259f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 260f84fdff0SXiaoyan Zhang return -ENOMEM; 261f84fdff0SXiaoyan Zhang ret = ((union acpi_object *)output.pointer)->integer.value; 262f84fdff0SXiaoyan Zhang if (ret < ARRAY_SIZE(info) - 1) 263f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 264f84fdff0SXiaoyan Zhang else 265f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 266f84fdff0SXiaoyan Zhang info[ARRAY_SIZE(info)-1]); 267f84fdff0SXiaoyan Zhang kfree(output.pointer); 268f84fdff0SXiaoyan Zhang return status; 269f84fdff0SXiaoyan Zhang } 270f84fdff0SXiaoyan Zhang 27181198078SXiaoyan Zhang static ssize_t tpm_show_ppi_response(struct device *dev, 272f84fdff0SXiaoyan Zhang struct device_attribute *attr, 273f84fdff0SXiaoyan Zhang char *buf) 274f84fdff0SXiaoyan Zhang { 275f84fdff0SXiaoyan Zhang acpi_handle handle; 276f84fdff0SXiaoyan Zhang acpi_status status; 277f84fdff0SXiaoyan Zhang struct acpi_object_list input; 278f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 279f84fdff0SXiaoyan Zhang union acpi_object params[4]; 280f84fdff0SXiaoyan Zhang union acpi_object *ret_obj; 281f84fdff0SXiaoyan Zhang u64 req; 282f84fdff0SXiaoyan Zhang 283f84fdff0SXiaoyan Zhang input.count = 4; 284f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_GETRSP); 285f84fdff0SXiaoyan Zhang input.pointer = params; 286f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 287f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 288f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 289f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 290f84fdff0SXiaoyan Zhang return -ENXIO; 291f84fdff0SXiaoyan Zhang 292f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 293f84fdff0SXiaoyan Zhang ACPI_TYPE_PACKAGE); 294f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 295f84fdff0SXiaoyan Zhang return -ENOMEM; 296f84fdff0SXiaoyan Zhang /* 297f84fdff0SXiaoyan Zhang * parameter output.pointer should be of package type, including 298f84fdff0SXiaoyan Zhang * 3 integers. The first means function return code, the second means 299f84fdff0SXiaoyan Zhang * most recent TPM operation request, and the last means response to 300f84fdff0SXiaoyan Zhang * the most recent TPM operation request. Only if the first is 0, and 301f84fdff0SXiaoyan Zhang * the second integer is not 0, the response makes sense. 302f84fdff0SXiaoyan Zhang */ 303f84fdff0SXiaoyan Zhang ret_obj = ((union acpi_object *)output.pointer)->package.elements; 304f84fdff0SXiaoyan Zhang if (ret_obj->type != ACPI_TYPE_INTEGER) { 305f84fdff0SXiaoyan Zhang status = -EINVAL; 306f84fdff0SXiaoyan Zhang goto cleanup; 307f84fdff0SXiaoyan Zhang } 308f84fdff0SXiaoyan Zhang if (ret_obj->integer.value) { 309f84fdff0SXiaoyan Zhang status = -EFAULT; 310f84fdff0SXiaoyan Zhang goto cleanup; 311f84fdff0SXiaoyan Zhang } 312f84fdff0SXiaoyan Zhang ret_obj++; 313f84fdff0SXiaoyan Zhang if (ret_obj->type != ACPI_TYPE_INTEGER) { 314f84fdff0SXiaoyan Zhang status = -EINVAL; 315f84fdff0SXiaoyan Zhang goto cleanup; 316f84fdff0SXiaoyan Zhang } 317f84fdff0SXiaoyan Zhang if (ret_obj->integer.value) { 318f84fdff0SXiaoyan Zhang req = ret_obj->integer.value; 319f84fdff0SXiaoyan Zhang ret_obj++; 320f84fdff0SXiaoyan Zhang if (ret_obj->type != ACPI_TYPE_INTEGER) { 321f84fdff0SXiaoyan Zhang status = -EINVAL; 322f84fdff0SXiaoyan Zhang goto cleanup; 323f84fdff0SXiaoyan Zhang } 324f84fdff0SXiaoyan Zhang if (ret_obj->integer.value == 0) 325f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 326f84fdff0SXiaoyan Zhang "0: Success"); 327f84fdff0SXiaoyan Zhang else if (ret_obj->integer.value == 0xFFFFFFF0) 328f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 329f84fdff0SXiaoyan Zhang "0xFFFFFFF0: User Abort"); 330f84fdff0SXiaoyan Zhang else if (ret_obj->integer.value == 0xFFFFFFF1) 331f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 332f84fdff0SXiaoyan Zhang "0xFFFFFFF1: BIOS Failure"); 333f84fdff0SXiaoyan Zhang else if (ret_obj->integer.value >= 1 && 334f84fdff0SXiaoyan Zhang ret_obj->integer.value <= 0x00000FFF) 335f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 336f84fdff0SXiaoyan Zhang req, ret_obj->integer.value, 337f84fdff0SXiaoyan Zhang "Corresponding TPM error"); 338f84fdff0SXiaoyan Zhang else 339f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 340f84fdff0SXiaoyan Zhang req, ret_obj->integer.value, 341f84fdff0SXiaoyan Zhang "Error"); 342f84fdff0SXiaoyan Zhang } else { 343f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 344f84fdff0SXiaoyan Zhang ret_obj->integer.value, "No Recent Request"); 345f84fdff0SXiaoyan Zhang } 346f84fdff0SXiaoyan Zhang cleanup: 347f84fdff0SXiaoyan Zhang kfree(output.pointer); 348f84fdff0SXiaoyan Zhang return status; 349f84fdff0SXiaoyan Zhang } 350f84fdff0SXiaoyan Zhang 351f84fdff0SXiaoyan Zhang static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) 352f84fdff0SXiaoyan Zhang { 353f84fdff0SXiaoyan Zhang char *str = buf; 354f84fdff0SXiaoyan Zhang char version[PPI_VERSION_LEN]; 355f84fdff0SXiaoyan Zhang acpi_handle handle; 356f84fdff0SXiaoyan Zhang acpi_status status; 357f84fdff0SXiaoyan Zhang struct acpi_object_list input; 358f84fdff0SXiaoyan Zhang struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 359f84fdff0SXiaoyan Zhang union acpi_object params[4]; 360f84fdff0SXiaoyan Zhang union acpi_object obj; 361f84fdff0SXiaoyan Zhang int i; 362f84fdff0SXiaoyan Zhang u32 ret; 363f84fdff0SXiaoyan Zhang char *info[] = { 364f84fdff0SXiaoyan Zhang "Not implemented", 365f84fdff0SXiaoyan Zhang "BIOS only", 366f84fdff0SXiaoyan Zhang "Blocked for OS by BIOS", 367f84fdff0SXiaoyan Zhang "User required", 368f84fdff0SXiaoyan Zhang "User not required", 369f84fdff0SXiaoyan Zhang }; 370f84fdff0SXiaoyan Zhang input.count = 4; 371f84fdff0SXiaoyan Zhang ppi_assign_params(params, TPM_PPI_FN_VERSION); 372f84fdff0SXiaoyan Zhang input.pointer = params; 373f84fdff0SXiaoyan Zhang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 374f84fdff0SXiaoyan Zhang ACPI_UINT32_MAX, ppi_callback, NULL, 375f84fdff0SXiaoyan Zhang tpm_device_name, &handle); 376f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 377f84fdff0SXiaoyan Zhang return -ENXIO; 378f84fdff0SXiaoyan Zhang 379f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 380f84fdff0SXiaoyan Zhang ACPI_TYPE_STRING); 381f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 382f84fdff0SXiaoyan Zhang return -ENOMEM; 383f84fdff0SXiaoyan Zhang 384f84fdff0SXiaoyan Zhang strncpy(version, 385f84fdff0SXiaoyan Zhang ((union acpi_object *)output.pointer)->string.pointer, 386f84fdff0SXiaoyan Zhang PPI_VERSION_LEN); 387f84fdff0SXiaoyan Zhang kfree(output.pointer); 388f84fdff0SXiaoyan Zhang output.length = ACPI_ALLOCATE_BUFFER; 389f84fdff0SXiaoyan Zhang output.pointer = NULL; 390f84fdff0SXiaoyan Zhang if (strcmp(version, "1.2") == -1) 391f84fdff0SXiaoyan Zhang return -EPERM; 392f84fdff0SXiaoyan Zhang 393f84fdff0SXiaoyan Zhang params[2].integer.value = TPM_PPI_FN_GETOPR; 394f84fdff0SXiaoyan Zhang params[3].package.count = 1; 395f84fdff0SXiaoyan Zhang obj.type = ACPI_TYPE_INTEGER; 396f84fdff0SXiaoyan Zhang params[3].package.elements = &obj; 397f84fdff0SXiaoyan Zhang for (i = start; i <= end; i++) { 398f84fdff0SXiaoyan Zhang obj.integer.value = i; 399f84fdff0SXiaoyan Zhang status = acpi_evaluate_object_typed(handle, "_DSM", 400f84fdff0SXiaoyan Zhang &input, &output, ACPI_TYPE_INTEGER); 401f84fdff0SXiaoyan Zhang if (ACPI_FAILURE(status)) 402f84fdff0SXiaoyan Zhang return -ENOMEM; 403f84fdff0SXiaoyan Zhang 404f84fdff0SXiaoyan Zhang ret = ((union acpi_object *)output.pointer)->integer.value; 405f84fdff0SXiaoyan Zhang if (ret > 0 && ret < ARRAY_SIZE(info)) 406f84fdff0SXiaoyan Zhang str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 407f84fdff0SXiaoyan Zhang i, ret, info[ret]); 408f84fdff0SXiaoyan Zhang kfree(output.pointer); 409f84fdff0SXiaoyan Zhang output.length = ACPI_ALLOCATE_BUFFER; 410f84fdff0SXiaoyan Zhang output.pointer = NULL; 411f84fdff0SXiaoyan Zhang } 412f84fdff0SXiaoyan Zhang return str - buf; 413f84fdff0SXiaoyan Zhang } 414f84fdff0SXiaoyan Zhang 41581198078SXiaoyan Zhang static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 41681198078SXiaoyan Zhang struct device_attribute *attr, 41781198078SXiaoyan Zhang char *buf) 418f84fdff0SXiaoyan Zhang { 419f84fdff0SXiaoyan Zhang return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); 420f84fdff0SXiaoyan Zhang } 421f84fdff0SXiaoyan Zhang 42281198078SXiaoyan Zhang static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 42381198078SXiaoyan Zhang struct device_attribute *attr, 42481198078SXiaoyan Zhang char *buf) 425f84fdff0SXiaoyan Zhang { 426f84fdff0SXiaoyan Zhang return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); 427f84fdff0SXiaoyan Zhang } 428f84fdff0SXiaoyan Zhang 429f84fdff0SXiaoyan Zhang static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 430f84fdff0SXiaoyan Zhang static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 431f84fdff0SXiaoyan Zhang tpm_show_ppi_request, tpm_store_ppi_request); 432f84fdff0SXiaoyan Zhang static DEVICE_ATTR(transition_action, S_IRUGO, 433f84fdff0SXiaoyan Zhang tpm_show_ppi_transition_action, NULL); 434f84fdff0SXiaoyan Zhang static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 435f84fdff0SXiaoyan Zhang static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 436f84fdff0SXiaoyan Zhang static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 437f84fdff0SXiaoyan Zhang 438f84fdff0SXiaoyan Zhang static struct attribute *ppi_attrs[] = { 439f84fdff0SXiaoyan Zhang &dev_attr_version.attr, 440f84fdff0SXiaoyan Zhang &dev_attr_request.attr, 441f84fdff0SXiaoyan Zhang &dev_attr_transition_action.attr, 442f84fdff0SXiaoyan Zhang &dev_attr_response.attr, 443f84fdff0SXiaoyan Zhang &dev_attr_tcg_operations.attr, 444f84fdff0SXiaoyan Zhang &dev_attr_vs_operations.attr, NULL, 445f84fdff0SXiaoyan Zhang }; 446f84fdff0SXiaoyan Zhang static struct attribute_group ppi_attr_grp = { 447*1631cfb7SGang Wei .name = "ppi", 448f84fdff0SXiaoyan Zhang .attrs = ppi_attrs 449f84fdff0SXiaoyan Zhang }; 450f84fdff0SXiaoyan Zhang 451*1631cfb7SGang Wei int tpm_add_ppi(struct kobject *parent) 452f84fdff0SXiaoyan Zhang { 453*1631cfb7SGang Wei return sysfs_create_group(parent, &ppi_attr_grp); 454f84fdff0SXiaoyan Zhang } 455*1631cfb7SGang Wei EXPORT_SYMBOL_GPL(tpm_add_ppi); 456*1631cfb7SGang Wei 457*1631cfb7SGang Wei void tpm_remove_ppi(struct kobject *parent) 458*1631cfb7SGang Wei { 459*1631cfb7SGang Wei sysfs_remove_group(parent, &ppi_attr_grp); 460*1631cfb7SGang Wei } 461*1631cfb7SGang Wei EXPORT_SYMBOL_GPL(tpm_remove_ppi); 462f84fdff0SXiaoyan Zhang 463f84fdff0SXiaoyan Zhang MODULE_LICENSE("GPL"); 464