vmgenid.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  4. *
  5. * The "Virtual Machine Generation ID" is exposed via ACPI or DT and changes when a
  6. * virtual machine forks or is cloned. This driver exists for shepherding that
  7. * information to random.c.
  8. */
  9. #include <linux/acpi.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/random.h>
  15. ACPI_MODULE_NAME("vmgenid");
  16. enum { VMGENID_SIZE = 16 };
  17. struct vmgenid_state {
  18. u8 *next_id;
  19. u8 this_id[VMGENID_SIZE];
  20. };
  21. static void vmgenid_notify(struct device *device)
  22. {
  23. struct vmgenid_state *state = device->driver_data;
  24. u8 old_id[VMGENID_SIZE];
  25. memcpy(old_id, state->this_id, sizeof(old_id));
  26. memcpy(state->this_id, state->next_id, sizeof(state->this_id));
  27. if (!memcmp(old_id, state->this_id, sizeof(old_id)))
  28. return;
  29. add_vmfork_randomness(state->this_id, sizeof(state->this_id));
  30. }
  31. static void setup_vmgenid_state(struct vmgenid_state *state, void *virt_addr)
  32. {
  33. state->next_id = virt_addr;
  34. memcpy(state->this_id, state->next_id, sizeof(state->this_id));
  35. add_device_randomness(state->this_id, sizeof(state->this_id));
  36. }
  37. #ifdef CONFIG_ACPI
  38. static void vmgenid_acpi_handler(acpi_handle __always_unused handle,
  39. u32 __always_unused event, void *dev)
  40. {
  41. vmgenid_notify(dev);
  42. }
  43. static int vmgenid_add_acpi(struct device *dev, struct vmgenid_state *state)
  44. {
  45. struct acpi_device *device = ACPI_COMPANION(dev);
  46. struct acpi_buffer parsed = { ACPI_ALLOCATE_BUFFER };
  47. union acpi_object *obj;
  48. phys_addr_t phys_addr;
  49. acpi_status status;
  50. void *virt_addr;
  51. int ret = 0;
  52. status = acpi_evaluate_object(device->handle, "ADDR", NULL, &parsed);
  53. if (ACPI_FAILURE(status)) {
  54. ACPI_EXCEPTION((AE_INFO, status, "Evaluating ADDR"));
  55. return -ENODEV;
  56. }
  57. obj = parsed.pointer;
  58. if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2 ||
  59. obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
  60. obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
  61. ret = -EINVAL;
  62. goto out;
  63. }
  64. phys_addr = (obj->package.elements[0].integer.value << 0) |
  65. (obj->package.elements[1].integer.value << 32);
  66. virt_addr = devm_memremap(&device->dev, phys_addr, VMGENID_SIZE, MEMREMAP_WB);
  67. if (IS_ERR(virt_addr)) {
  68. ret = PTR_ERR(virt_addr);
  69. goto out;
  70. }
  71. setup_vmgenid_state(state, virt_addr);
  72. status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
  73. vmgenid_acpi_handler, dev);
  74. if (ACPI_FAILURE(status)) {
  75. ret = -ENODEV;
  76. goto out;
  77. }
  78. dev->driver_data = state;
  79. out:
  80. ACPI_FREE(parsed.pointer);
  81. return ret;
  82. }
  83. #else
  84. static int vmgenid_add_acpi(struct device *dev, struct vmgenid_state *state)
  85. {
  86. return -EINVAL;
  87. }
  88. #endif
  89. static irqreturn_t vmgenid_of_irq_handler(int __always_unused irq, void *dev)
  90. {
  91. vmgenid_notify(dev);
  92. return IRQ_HANDLED;
  93. }
  94. static int vmgenid_add_of(struct platform_device *pdev,
  95. struct vmgenid_state *state)
  96. {
  97. void *virt_addr;
  98. int ret;
  99. virt_addr = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
  100. if (IS_ERR(virt_addr))
  101. return PTR_ERR(virt_addr);
  102. setup_vmgenid_state(state, virt_addr);
  103. ret = platform_get_irq(pdev, 0);
  104. if (ret < 0)
  105. return ret;
  106. ret = devm_request_irq(&pdev->dev, ret, vmgenid_of_irq_handler,
  107. IRQF_SHARED, "vmgenid", &pdev->dev);
  108. if (ret < 0)
  109. return ret;
  110. pdev->dev.driver_data = state;
  111. return 0;
  112. }
  113. static int vmgenid_add(struct platform_device *pdev)
  114. {
  115. struct device *dev = &pdev->dev;
  116. struct vmgenid_state *state;
  117. int ret;
  118. state = devm_kmalloc(dev, sizeof(*state), GFP_KERNEL);
  119. if (!state)
  120. return -ENOMEM;
  121. if (dev->of_node)
  122. ret = vmgenid_add_of(pdev, state);
  123. else
  124. ret = vmgenid_add_acpi(dev, state);
  125. if (ret < 0)
  126. devm_kfree(dev, state);
  127. return ret;
  128. }
  129. static const struct of_device_id vmgenid_of_ids[] = {
  130. { .compatible = "microsoft,vmgenid", },
  131. { },
  132. };
  133. MODULE_DEVICE_TABLE(of, vmgenid_of_ids);
  134. static const struct acpi_device_id vmgenid_acpi_ids[] = {
  135. { "VMGENCTR", 0 },
  136. { "VM_GEN_COUNTER", 0 },
  137. { }
  138. };
  139. MODULE_DEVICE_TABLE(acpi, vmgenid_acpi_ids);
  140. static struct platform_driver vmgenid_plaform_driver = {
  141. .probe = vmgenid_add,
  142. .driver = {
  143. .name = "vmgenid",
  144. .acpi_match_table = vmgenid_acpi_ids,
  145. .of_match_table = vmgenid_of_ids,
  146. },
  147. };
  148. module_platform_driver(vmgenid_plaform_driver)
  149. MODULE_DESCRIPTION("Virtual Machine Generation ID");
  150. MODULE_LICENSE("GPL v2");
  151. MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");