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