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