1 /* 2 * QTest testcase for acpi-erst 3 * 4 * Copyright (c) 2021 Oracle 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include <glib/gstdio.h> 12 #include "libqos/libqos-pc.h" 13 #include "libqtest.h" 14 15 #include "hw/pci/pci.h" 16 17 static void save_fn(QPCIDevice *dev, int devfn, void *data) 18 { 19 QPCIDevice **pdev = (QPCIDevice **) data; 20 21 *pdev = dev; 22 } 23 24 static QPCIDevice *get_erst_device(QPCIBus *pcibus) 25 { 26 QPCIDevice *dev; 27 28 dev = NULL; 29 qpci_device_foreach(pcibus, 30 PCI_VENDOR_ID_REDHAT, 31 PCI_DEVICE_ID_REDHAT_ACPI_ERST, 32 save_fn, &dev); 33 g_assert(dev != NULL); 34 35 return dev; 36 } 37 38 typedef struct _ERSTState { 39 QOSState *qs; 40 QPCIBar reg_bar, mem_bar; 41 uint64_t reg_barsize, mem_barsize; 42 QPCIDevice *dev; 43 } ERSTState; 44 45 #define ACTION 0 46 #define VALUE 8 47 48 static const char *reg2str(unsigned reg) 49 { 50 switch (reg) { 51 case 0: 52 return "ACTION"; 53 case 8: 54 return "VALUE"; 55 default: 56 return NULL; 57 } 58 } 59 60 static inline uint32_t in_reg32(ERSTState *s, unsigned reg) 61 { 62 const char *name = reg2str(reg); 63 uint32_t res; 64 65 res = qpci_io_readl(s->dev, s->reg_bar, reg); 66 g_test_message("*%s -> %08x", name, res); 67 68 return res; 69 } 70 71 static inline uint64_t in_reg64(ERSTState *s, unsigned reg) 72 { 73 const char *name = reg2str(reg); 74 uint64_t res; 75 76 res = qpci_io_readq(s->dev, s->reg_bar, reg); 77 g_test_message("*%s -> %016" PRIx64, name, res); 78 79 return res; 80 } 81 82 static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v) 83 { 84 const char *name = reg2str(reg); 85 86 g_test_message("%08x -> *%s", v, name); 87 qpci_io_writel(s->dev, s->reg_bar, reg, v); 88 } 89 90 static void cleanup_vm(ERSTState *s) 91 { 92 g_free(s->dev); 93 qtest_shutdown(s->qs); 94 } 95 96 static void setup_vm_cmd(ERSTState *s, const char *cmd) 97 { 98 const char *arch = qtest_get_arch(); 99 100 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 101 s->qs = qtest_pc_boot("%s", cmd); 102 } else { 103 g_printerr("erst-test tests are only available on x86\n"); 104 exit(EXIT_FAILURE); 105 } 106 s->dev = get_erst_device(s->qs->pcibus); 107 108 s->reg_bar = qpci_iomap(s->dev, 0, &s->reg_barsize); 109 g_assert_cmpuint(s->reg_barsize, ==, 16); 110 111 s->mem_bar = qpci_iomap(s->dev, 1, &s->mem_barsize); 112 g_assert_cmpuint(s->mem_barsize, ==, 0x2000); 113 114 qpci_device_enable(s->dev); 115 } 116 117 static void test_acpi_erst_basic(void) 118 { 119 ERSTState state; 120 uint64_t log_address_range; 121 uint64_t log_address_length; 122 uint32_t log_address_attr; 123 124 setup_vm_cmd(&state, 125 "-object memory-backend-file," 126 "mem-path=acpi-erst.XXXXXX," 127 "size=64K," 128 "share=on," 129 "id=nvram " 130 "-device acpi-erst," 131 "memdev=nvram"); 132 133 out_reg32(&state, ACTION, 0xD); 134 log_address_range = in_reg64(&state, VALUE); 135 out_reg32(&state, ACTION, 0xE); 136 log_address_length = in_reg64(&state, VALUE); 137 out_reg32(&state, ACTION, 0xF); 138 log_address_attr = in_reg32(&state, VALUE); 139 140 /* Check log_address_range is not 0, ~0 or base */ 141 g_assert_cmpuint(log_address_range, !=, 0ULL); 142 g_assert_cmpuint(log_address_range, !=, ~0ULL); 143 g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr); 144 g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr); 145 146 /* Check log_address_length is bar1_size */ 147 g_assert_cmpuint(log_address_length, ==, state.mem_barsize); 148 149 /* Check log_address_attr is 0 */ 150 g_assert_cmpuint(log_address_attr, ==, 0); 151 152 cleanup_vm(&state); 153 } 154 155 int main(int argc, char **argv) 156 { 157 g_test_init(&argc, &argv, NULL); 158 qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic); 159 return g_test_run(); 160 } 161