vmclock.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Virtual Machine Clock Device
  3. *
  4. * Copyright © 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  5. *
  6. * Authors: David Woodhouse <dwmw2@infradead.org>
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  9. * See the COPYING file in the top-level directory.
  10. */
  11. #include "qemu/osdep.h"
  12. #include "qapi/error.h"
  13. #include "qemu/module.h"
  14. #include "hw/i386/e820_memory_layout.h"
  15. #include "hw/acpi/acpi.h"
  16. #include "hw/acpi/aml-build.h"
  17. #include "hw/acpi/vmclock.h"
  18. #include "hw/nvram/fw_cfg.h"
  19. #include "hw/qdev-properties.h"
  20. #include "hw/qdev-properties-system.h"
  21. #include "migration/vmstate.h"
  22. #include "system/reset.h"
  23. #include "standard-headers/linux/vmclock-abi.h"
  24. void vmclock_build_acpi(VmclockState *vms, GArray *table_data,
  25. BIOSLinker *linker, const char *oem_id)
  26. {
  27. Aml *ssdt, *dev, *scope, *crs;
  28. AcpiTable table = { .sig = "SSDT", .rev = 1,
  29. .oem_id = oem_id, .oem_table_id = "VMCLOCK" };
  30. /* Put VMCLOCK into a separate SSDT table */
  31. acpi_table_begin(&table, table_data);
  32. ssdt = init_aml_allocator();
  33. scope = aml_scope("\\_SB");
  34. dev = aml_device("VCLK");
  35. aml_append(dev, aml_name_decl("_HID", aml_string("AMZNC10C")));
  36. aml_append(dev, aml_name_decl("_CID", aml_string("VMCLOCK")));
  37. aml_append(dev, aml_name_decl("_DDN", aml_string("VMCLOCK")));
  38. /* Simple status method */
  39. aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
  40. crs = aml_resource_template();
  41. aml_append(crs, aml_qword_memory(AML_POS_DECODE,
  42. AML_MIN_FIXED, AML_MAX_FIXED,
  43. AML_CACHEABLE, AML_READ_ONLY,
  44. 0xffffffffffffffffULL,
  45. vms->physaddr,
  46. vms->physaddr + VMCLOCK_SIZE - 1,
  47. 0, VMCLOCK_SIZE));
  48. aml_append(dev, aml_name_decl("_CRS", crs));
  49. aml_append(scope, dev);
  50. aml_append(ssdt, scope);
  51. g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
  52. acpi_table_end(linker, &table);
  53. free_aml_allocator();
  54. }
  55. static void vmclock_update_guest(VmclockState *vms)
  56. {
  57. uint64_t disruption_marker;
  58. uint32_t seq_count;
  59. if (!vms->clk) {
  60. return;
  61. }
  62. seq_count = le32_to_cpu(vms->clk->seq_count) | 1;
  63. vms->clk->seq_count = cpu_to_le32(seq_count);
  64. /* These barriers pair with read barriers in the guest */
  65. smp_wmb();
  66. disruption_marker = le64_to_cpu(vms->clk->disruption_marker);
  67. disruption_marker++;
  68. vms->clk->disruption_marker = cpu_to_le64(disruption_marker);
  69. /* These barriers pair with read barriers in the guest */
  70. smp_wmb();
  71. vms->clk->seq_count = cpu_to_le32(seq_count + 1);
  72. }
  73. /*
  74. * After restoring an image, we need to update the guest memory to notify
  75. * it of clock disruption.
  76. */
  77. static int vmclock_post_load(void *opaque, int version_id)
  78. {
  79. VmclockState *vms = opaque;
  80. vmclock_update_guest(vms);
  81. return 0;
  82. }
  83. static const VMStateDescription vmstate_vmclock = {
  84. .name = "vmclock",
  85. .version_id = 1,
  86. .minimum_version_id = 1,
  87. .post_load = vmclock_post_load,
  88. .fields = (const VMStateField[]) {
  89. VMSTATE_UINT64(physaddr, VmclockState),
  90. VMSTATE_END_OF_LIST()
  91. },
  92. };
  93. static void vmclock_handle_reset(void *opaque)
  94. {
  95. VmclockState *vms = VMCLOCK(opaque);
  96. if (!memory_region_is_mapped(&vms->clk_page)) {
  97. memory_region_add_subregion_overlap(get_system_memory(),
  98. vms->physaddr,
  99. &vms->clk_page, 0);
  100. }
  101. }
  102. static void vmclock_realize(DeviceState *dev, Error **errp)
  103. {
  104. VmclockState *vms = VMCLOCK(dev);
  105. /*
  106. * Given that this function is executing, there is at least one VMCLOCK
  107. * device. Check if there are several.
  108. */
  109. if (!find_vmclock_dev()) {
  110. error_setg(errp, "at most one %s device is permitted", TYPE_VMCLOCK);
  111. return;
  112. }
  113. vms->physaddr = VMCLOCK_ADDR;
  114. e820_add_entry(vms->physaddr, VMCLOCK_SIZE, E820_RESERVED);
  115. memory_region_init_ram(&vms->clk_page, OBJECT(dev), "vmclock_page",
  116. VMCLOCK_SIZE, &error_abort);
  117. memory_region_set_enabled(&vms->clk_page, true);
  118. vms->clk = memory_region_get_ram_ptr(&vms->clk_page);
  119. memset(vms->clk, 0, VMCLOCK_SIZE);
  120. vms->clk->magic = cpu_to_le32(VMCLOCK_MAGIC);
  121. vms->clk->size = cpu_to_le16(VMCLOCK_SIZE);
  122. vms->clk->version = cpu_to_le16(1);
  123. /* These are all zero and thus default, but be explicit */
  124. vms->clk->clock_status = VMCLOCK_STATUS_UNKNOWN;
  125. vms->clk->counter_id = VMCLOCK_COUNTER_INVALID;
  126. qemu_register_reset(vmclock_handle_reset, vms);
  127. vmclock_update_guest(vms);
  128. }
  129. static void vmclock_device_class_init(ObjectClass *klass, void *data)
  130. {
  131. DeviceClass *dc = DEVICE_CLASS(klass);
  132. dc->vmsd = &vmstate_vmclock;
  133. dc->realize = vmclock_realize;
  134. dc->hotpluggable = false;
  135. set_bit(DEVICE_CATEGORY_MISC, dc->categories);
  136. }
  137. static const TypeInfo vmclock_device_info = {
  138. .name = TYPE_VMCLOCK,
  139. .parent = TYPE_DEVICE,
  140. .instance_size = sizeof(VmclockState),
  141. .class_init = vmclock_device_class_init,
  142. };
  143. static void vmclock_register_types(void)
  144. {
  145. type_register_static(&vmclock_device_info);
  146. }
  147. type_init(vmclock_register_types)