1#include <linux/acpi.h> 2#include "tpm.h" 3 4#define TPM_PPI_REVISION_ID 1 5#define TPM_PPI_FN_VERSION 1 6#define TPM_PPI_FN_SUBREQ 2 7#define TPM_PPI_FN_GETREQ 3 8#define TPM_PPI_FN_GETACT 4 9#define TPM_PPI_FN_GETRSP 5 10#define TPM_PPI_FN_SUBREQ2 7 11#define TPM_PPI_FN_GETOPR 8 12#define PPI_TPM_REQ_MAX 22 13#define PPI_VS_REQ_START 128 14#define PPI_VS_REQ_END 255 15#define PPI_VERSION_LEN 3 16 17static const u8 tpm_ppi_uuid[] = { 18 0xA6, 0xFA, 0xDD, 0x3D, 19 0x1B, 0x36, 20 0xB4, 0x4E, 21 0xA4, 0x24, 22 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 23}; 24 25static char tpm_ppi_version[PPI_VERSION_LEN + 1]; 26static acpi_handle tpm_ppi_handle; 27 28static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, 29 void **return_value) 30{ 31 union acpi_object *obj; 32 33 if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 34 1 << TPM_PPI_FN_VERSION)) 35 return AE_OK; 36 37 /* Cache version string */ 38 obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, 39 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, 40 NULL, ACPI_TYPE_STRING); 41 if (obj) { 42 strlcpy(tpm_ppi_version, obj->string.pointer, 43 PPI_VERSION_LEN + 1); 44 ACPI_FREE(obj); 45 } 46 47 *return_value = handle; 48 49 return AE_CTRL_TERMINATE; 50} 51 52static inline union acpi_object * 53tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) 54{ 55 BUG_ON(!tpm_ppi_handle); 56 return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, 57 TPM_PPI_REVISION_ID, func, argv4, type); 58} 59 60static ssize_t tpm_show_ppi_version(struct device *dev, 61 struct device_attribute *attr, char *buf) 62{ 63 return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); 64} 65 66static ssize_t tpm_show_ppi_request(struct device *dev, 67 struct device_attribute *attr, char *buf) 68{ 69 ssize_t size = -EINVAL; 70 union acpi_object *obj; 71 72 obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); 73 if (!obj) 74 return -ENXIO; 75 76 /* 77 * output.pointer should be of package type, including two integers. 78 * The first is function return code, 0 means success and 1 means 79 * error. The second is pending TPM operation requested by the OS, 0 80 * means none and >0 means operation value. 81 */ 82 if (obj->package.count == 2 && 83 obj->package.elements[0].type == ACPI_TYPE_INTEGER && 84 obj->package.elements[1].type == ACPI_TYPE_INTEGER) { 85 if (obj->package.elements[0].integer.value) 86 size = -EFAULT; 87 else 88 size = scnprintf(buf, PAGE_SIZE, "%llu\n", 89 obj->package.elements[1].integer.value); 90 } 91 92 ACPI_FREE(obj); 93 94 return size; 95} 96 97static ssize_t tpm_store_ppi_request(struct device *dev, 98 struct device_attribute *attr, 99 const char *buf, size_t count) 100{ 101 u32 req; 102 u64 ret; 103 int func = TPM_PPI_FN_SUBREQ; 104 union acpi_object *obj, tmp; 105 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); 106 107 /* 108 * the function to submit TPM operation request to pre-os environment 109 * is updated with function index from SUBREQ to SUBREQ2 since PPI 110 * version 1.1 111 */ 112 if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 113 1 << TPM_PPI_FN_SUBREQ2)) 114 func = TPM_PPI_FN_SUBREQ2; 115 116 /* 117 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 118 * accept buffer/string/integer type, but some BIOS accept buffer/ 119 * string/package type. For PPI version 1.0 and 1.1, use buffer type 120 * for compatibility, and use package type since 1.2 according to spec. 121 */ 122 if (strcmp(tpm_ppi_version, "1.2") < 0) { 123 if (sscanf(buf, "%d", &req) != 1) 124 return -EINVAL; 125 argv4.type = ACPI_TYPE_BUFFER; 126 argv4.buffer.length = sizeof(req); 127 argv4.buffer.pointer = (u8 *)&req; 128 } else { 129 tmp.type = ACPI_TYPE_INTEGER; 130 if (sscanf(buf, "%llu", &tmp.integer.value) != 1) 131 return -EINVAL; 132 } 133 134 obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); 135 if (!obj) { 136 return -ENXIO; 137 } else { 138 ret = obj->integer.value; 139 ACPI_FREE(obj); 140 } 141 142 if (ret == 0) 143 return (acpi_status)count; 144 145 return (ret == 1) ? -EPERM : -EFAULT; 146} 147 148static ssize_t tpm_show_ppi_transition_action(struct device *dev, 149 struct device_attribute *attr, 150 char *buf) 151{ 152 u32 ret; 153 acpi_status status; 154 union acpi_object *obj = NULL; 155 union acpi_object tmp = { 156 .buffer.type = ACPI_TYPE_BUFFER, 157 .buffer.length = 0, 158 .buffer.pointer = NULL 159 }; 160 161 static char *info[] = { 162 "None", 163 "Shutdown", 164 "Reboot", 165 "OS Vendor-specific", 166 "Error", 167 }; 168 169 /* 170 * PPI spec defines params[3].type as empty package, but some platforms 171 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 172 * compatibility, define params[3].type as buffer, if PPI version < 1.2 173 */ 174 if (strcmp(tpm_ppi_version, "1.2") < 0) 175 obj = &tmp; 176 obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); 177 if (!obj) { 178 return -ENXIO; 179 } else { 180 ret = obj->integer.value; 181 ACPI_FREE(obj); 182 } 183 184 if (ret < ARRAY_SIZE(info) - 1) 185 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 186 else 187 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 188 info[ARRAY_SIZE(info)-1]); 189 return status; 190} 191 192static ssize_t tpm_show_ppi_response(struct device *dev, 193 struct device_attribute *attr, 194 char *buf) 195{ 196 acpi_status status = -EINVAL; 197 union acpi_object *obj, *ret_obj; 198 u64 req, res; 199 200 obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); 201 if (!obj) 202 return -ENXIO; 203 204 /* 205 * parameter output.pointer should be of package type, including 206 * 3 integers. The first means function return code, the second means 207 * most recent TPM operation request, and the last means response to 208 * the most recent TPM operation request. Only if the first is 0, and 209 * the second integer is not 0, the response makes sense. 210 */ 211 ret_obj = obj->package.elements; 212 if (obj->package.count < 3 || 213 ret_obj[0].type != ACPI_TYPE_INTEGER || 214 ret_obj[1].type != ACPI_TYPE_INTEGER || 215 ret_obj[2].type != ACPI_TYPE_INTEGER) 216 goto cleanup; 217 218 if (ret_obj[0].integer.value) { 219 status = -EFAULT; 220 goto cleanup; 221 } 222 223 req = ret_obj[1].integer.value; 224 res = ret_obj[2].integer.value; 225 if (req) { 226 if (res == 0) 227 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 228 "0: Success"); 229 else if (res == 0xFFFFFFF0) 230 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 231 "0xFFFFFFF0: User Abort"); 232 else if (res == 0xFFFFFFF1) 233 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 234 "0xFFFFFFF1: BIOS Failure"); 235 else if (res >= 1 && res <= 0x00000FFF) 236 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 237 req, res, "Corresponding TPM error"); 238 else 239 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 240 req, res, "Error"); 241 } else { 242 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 243 req, "No Recent Request"); 244 } 245 246cleanup: 247 ACPI_FREE(obj); 248 return status; 249} 250 251static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) 252{ 253 int i; 254 u32 ret; 255 char *str = buf; 256 union acpi_object *obj, tmp; 257 union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); 258 259 static char *info[] = { 260 "Not implemented", 261 "BIOS only", 262 "Blocked for OS by BIOS", 263 "User required", 264 "User not required", 265 }; 266 267 if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 268 1 << TPM_PPI_FN_GETOPR)) 269 return -EPERM; 270 271 tmp.integer.type = ACPI_TYPE_INTEGER; 272 for (i = start; i <= end; i++) { 273 tmp.integer.value = i; 274 obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); 275 if (!obj) { 276 return -ENOMEM; 277 } else { 278 ret = obj->integer.value; 279 ACPI_FREE(obj); 280 } 281 282 if (ret > 0 && ret < ARRAY_SIZE(info)) 283 str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 284 i, ret, info[ret]); 285 } 286 287 return str - buf; 288} 289 290static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 291 struct device_attribute *attr, 292 char *buf) 293{ 294 return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); 295} 296 297static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 298 struct device_attribute *attr, 299 char *buf) 300{ 301 return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); 302} 303 304static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 305static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 306 tpm_show_ppi_request, tpm_store_ppi_request); 307static DEVICE_ATTR(transition_action, S_IRUGO, 308 tpm_show_ppi_transition_action, NULL); 309static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 310static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 311static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 312 313static struct attribute *ppi_attrs[] = { 314 &dev_attr_version.attr, 315 &dev_attr_request.attr, 316 &dev_attr_transition_action.attr, 317 &dev_attr_response.attr, 318 &dev_attr_tcg_operations.attr, 319 &dev_attr_vs_operations.attr, NULL, 320}; 321static struct attribute_group ppi_attr_grp = { 322 .name = "ppi", 323 .attrs = ppi_attrs 324}; 325 326int tpm_add_ppi(struct kobject *parent) 327{ 328 /* Cache TPM ACPI handle and version string */ 329 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 330 ppi_callback, NULL, NULL, &tpm_ppi_handle); 331 return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0; 332} 333 334void tpm_remove_ppi(struct kobject *parent) 335{ 336 if (tpm_ppi_handle) 337 sysfs_remove_group(parent, &ppi_attr_grp); 338} 339