dell-smbios-example.c 4.9 KB

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