dell-smbios-example.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Sample application for SMBIOS communication over WMI interface
  4. * Performs the following:
  5. * - Simple cmd_class/cmd_select lookup for TPM information
  6. * - Simple query of known tokens and their values
  7. * - Simple activation of a token
  8. *
  9. * Copyright (C) 2017 Dell, Inc.
  10. */
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <sys/ioctl.h>
  16. #include <unistd.h>
  17. /* if uapi header isn't installed, this might not yet exist */
  18. #ifndef __packed
  19. #define __packed __attribute__((packed))
  20. #endif
  21. #include <linux/wmi.h>
  22. /* It would be better to discover these using udev, but for a simple
  23. * application they're hardcoded
  24. */
  25. static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
  26. static const char *token_sysfs =
  27. "/sys/bus/platform/devices/dell-smbios.0/tokens";
  28. static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
  29. {
  30. printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
  31. buffer->std.cmd_class, buffer->std.cmd_select,
  32. buffer->std.input[0], buffer->std.input[1],
  33. buffer->std.input[2], buffer->std.input[3],
  34. buffer->std.output[0], buffer->std.output[1],
  35. buffer->std.output[2], buffer->std.output[3]);
  36. }
  37. static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
  38. {
  39. int fd;
  40. int ret;
  41. fd = open(ioctl_devfs, O_NONBLOCK);
  42. ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
  43. close(fd);
  44. return ret;
  45. }
  46. static int find_token(__u16 token, __u16 *location, __u16 *value)
  47. {
  48. char location_sysfs[60];
  49. char value_sysfs[57];
  50. char buf[4096];
  51. FILE *f;
  52. int ret;
  53. ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
  54. if (ret < 0) {
  55. printf("sprintf value failed\n");
  56. return 2;
  57. }
  58. f = fopen(value_sysfs, "rb");
  59. if (!f) {
  60. printf("failed to open %s\n", value_sysfs);
  61. return 2;
  62. }
  63. fread(buf, 1, 4096, f);
  64. fclose(f);
  65. *value = (__u16) strtol(buf, NULL, 16);
  66. ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
  67. if (ret < 0) {
  68. printf("sprintf location failed\n");
  69. return 1;
  70. }
  71. f = fopen(location_sysfs, "rb");
  72. if (!f) {
  73. printf("failed to open %s\n", location_sysfs);
  74. return 2;
  75. }
  76. fread(buf, 1, 4096, f);
  77. fclose(f);
  78. *location = (__u16) strtol(buf, NULL, 16);
  79. if (*location)
  80. return 0;
  81. return 2;
  82. }
  83. static int token_is_active(__u16 *location, __u16 *cmpvalue,
  84. struct dell_wmi_smbios_buffer *buffer)
  85. {
  86. int ret;
  87. buffer->std.cmd_class = CLASS_TOKEN_READ;
  88. buffer->std.cmd_select = SELECT_TOKEN_STD;
  89. buffer->std.input[0] = *location;
  90. ret = run_wmi_smbios_cmd(buffer);
  91. if (ret != 0 || buffer->std.output[0] != 0)
  92. return ret;
  93. ret = (buffer->std.output[1] == *cmpvalue);
  94. return ret;
  95. }
  96. static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
  97. {
  98. __u16 location;
  99. __u16 value;
  100. int ret;
  101. ret = find_token(token, &location, &value);
  102. if (ret != 0) {
  103. printf("unable to find token %04x\n", token);
  104. return 1;
  105. }
  106. return token_is_active(&location, &value, buffer);
  107. }
  108. static int activate_token(struct dell_wmi_smbios_buffer *buffer,
  109. __u16 token)
  110. {
  111. __u16 location;
  112. __u16 value;
  113. int ret;
  114. ret = find_token(token, &location, &value);
  115. if (ret != 0) {
  116. printf("unable to find token %04x\n", token);
  117. return 1;
  118. }
  119. buffer->std.cmd_class = CLASS_TOKEN_WRITE;
  120. buffer->std.cmd_select = SELECT_TOKEN_STD;
  121. buffer->std.input[0] = location;
  122. buffer->std.input[1] = 1;
  123. ret = run_wmi_smbios_cmd(buffer);
  124. return ret;
  125. }
  126. static int query_buffer_size(__u64 *buffer_size)
  127. {
  128. FILE *f;
  129. f = fopen(ioctl_devfs, "rb");
  130. if (!f)
  131. return -EINVAL;
  132. fread(buffer_size, sizeof(__u64), 1, f);
  133. fclose(f);
  134. return EXIT_SUCCESS;
  135. }
  136. int main(void)
  137. {
  138. struct dell_wmi_smbios_buffer *buffer;
  139. int ret;
  140. __u64 value = 0;
  141. ret = query_buffer_size(&value);
  142. if (ret == EXIT_FAILURE || !value) {
  143. printf("Unable to read buffer size\n");
  144. goto out;
  145. }
  146. printf("Detected required buffer size %lld\n", value);
  147. buffer = malloc(value);
  148. if (buffer == NULL) {
  149. printf("failed to alloc memory for ioctl\n");
  150. ret = -ENOMEM;
  151. goto out;
  152. }
  153. buffer->length = value;
  154. /* simple SMBIOS call for looking up TPM info */
  155. buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
  156. buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
  157. buffer->std.input[0] = 2;
  158. ret = run_wmi_smbios_cmd(buffer);
  159. if (ret) {
  160. printf("smbios ioctl failed: %d\n", ret);
  161. ret = EXIT_FAILURE;
  162. goto out;
  163. }
  164. show_buffer(buffer);
  165. /* query some tokens */
  166. ret = query_token(CAPSULE_EN_TOKEN, buffer);
  167. printf("UEFI Capsule enabled token is: %d\n", ret);
  168. ret = query_token(CAPSULE_DIS_TOKEN, buffer);
  169. printf("UEFI Capsule disabled token is: %d\n", ret);
  170. /* activate UEFI capsule token if disabled */
  171. if (ret) {
  172. printf("Enabling UEFI capsule token");
  173. if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
  174. printf("activate failed\n");
  175. ret = -1;
  176. goto out;
  177. }
  178. }
  179. ret = EXIT_SUCCESS;
  180. out:
  181. free(buffer);
  182. return ret;
  183. }