188a07990SMichael Clark /* 288a07990SMichael Clark * QEMU SiFive Test Finisher 388a07990SMichael Clark * 488a07990SMichael Clark * Copyright (c) 2018 SiFive, Inc. 588a07990SMichael Clark * 688a07990SMichael Clark * Test finisher memory mapped device used to exit simulation 788a07990SMichael Clark * 888a07990SMichael Clark * This program is free software; you can redistribute it and/or modify it 988a07990SMichael Clark * under the terms and conditions of the GNU General Public License, 1088a07990SMichael Clark * version 2 or later, as published by the Free Software Foundation. 1188a07990SMichael Clark * 1288a07990SMichael Clark * This program is distributed in the hope it will be useful, but WITHOUT 1388a07990SMichael Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1488a07990SMichael Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1588a07990SMichael Clark * more details. 1688a07990SMichael Clark * 1788a07990SMichael Clark * You should have received a copy of the GNU General Public License along with 1888a07990SMichael Clark * this program. If not, see <http://www.gnu.org/licenses/>. 1988a07990SMichael Clark */ 2088a07990SMichael Clark 2188a07990SMichael Clark #include "qemu/osdep.h" 2288a07990SMichael Clark #include "hw/sysbus.h" 233e80f690SMarkus Armbruster #include "qapi/error.h" 24a2360c85SBin Meng #include "qemu/log.h" 250b8fa32fSMarkus Armbruster #include "qemu/module.h" 269a2551edSBin Meng #include "sysemu/runstate.h" 27650d103dSMarkus Armbruster #include "hw/hw.h" 2888a07990SMichael Clark #include "hw/riscv/sifive_test.h" 2988a07990SMichael Clark 3088a07990SMichael Clark static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) 3188a07990SMichael Clark { 3288a07990SMichael Clark return 0; 3388a07990SMichael Clark } 3488a07990SMichael Clark 3588a07990SMichael Clark static void sifive_test_write(void *opaque, hwaddr addr, 3688a07990SMichael Clark uint64_t val64, unsigned int size) 3788a07990SMichael Clark { 3888a07990SMichael Clark if (addr == 0) { 3988a07990SMichael Clark int status = val64 & 0xffff; 4088a07990SMichael Clark int code = (val64 >> 16) & 0xffff; 4188a07990SMichael Clark switch (status) { 4288a07990SMichael Clark case FINISHER_FAIL: 4388a07990SMichael Clark exit(code); 4488a07990SMichael Clark case FINISHER_PASS: 4588a07990SMichael Clark exit(0); 469a2551edSBin Meng case FINISHER_RESET: 479a2551edSBin Meng qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 489a2551edSBin Meng return; 4988a07990SMichael Clark default: 5088a07990SMichael Clark break; 5188a07990SMichael Clark } 5288a07990SMichael Clark } 53a2360c85SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: write: addr=0x%x val=0x%016" PRIx64 "\n", 5488a07990SMichael Clark __func__, (int)addr, val64); 5588a07990SMichael Clark } 5688a07990SMichael Clark 5788a07990SMichael Clark static const MemoryRegionOps sifive_test_ops = { 5888a07990SMichael Clark .read = sifive_test_read, 5988a07990SMichael Clark .write = sifive_test_write, 6088a07990SMichael Clark .endianness = DEVICE_NATIVE_ENDIAN, 6188a07990SMichael Clark .valid = { 62*ab3d207fSNathan Chancellor .min_access_size = 2, 6388a07990SMichael Clark .max_access_size = 4 6488a07990SMichael Clark } 6588a07990SMichael Clark }; 6688a07990SMichael Clark 6788a07990SMichael Clark static void sifive_test_init(Object *obj) 6888a07990SMichael Clark { 6988a07990SMichael Clark SiFiveTestState *s = SIFIVE_TEST(obj); 7088a07990SMichael Clark 7188a07990SMichael Clark memory_region_init_io(&s->mmio, obj, &sifive_test_ops, s, 7288a07990SMichael Clark TYPE_SIFIVE_TEST, 0x1000); 7388a07990SMichael Clark sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 7488a07990SMichael Clark } 7588a07990SMichael Clark 7688a07990SMichael Clark static const TypeInfo sifive_test_info = { 7788a07990SMichael Clark .name = TYPE_SIFIVE_TEST, 7888a07990SMichael Clark .parent = TYPE_SYS_BUS_DEVICE, 7988a07990SMichael Clark .instance_size = sizeof(SiFiveTestState), 8088a07990SMichael Clark .instance_init = sifive_test_init, 8188a07990SMichael Clark }; 8288a07990SMichael Clark 8388a07990SMichael Clark static void sifive_test_register_types(void) 8488a07990SMichael Clark { 8588a07990SMichael Clark type_register_static(&sifive_test_info); 8688a07990SMichael Clark } 8788a07990SMichael Clark 8888a07990SMichael Clark type_init(sifive_test_register_types) 8988a07990SMichael Clark 9088a07990SMichael Clark 9188a07990SMichael Clark /* 9288a07990SMichael Clark * Create Test device. 9388a07990SMichael Clark */ 9488a07990SMichael Clark DeviceState *sifive_test_create(hwaddr addr) 9588a07990SMichael Clark { 963e80f690SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST); 973c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 9888a07990SMichael Clark sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 9988a07990SMichael Clark return dev; 10088a07990SMichael Clark } 101