1*069852d1SJackson Donaldson /* 2*069852d1SJackson Donaldson * MAX78000 True Random Number Generator 3*069852d1SJackson Donaldson * 4*069852d1SJackson Donaldson * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com> 5*069852d1SJackson Donaldson * 6*069852d1SJackson Donaldson * SPDX-License-Identifier: GPL-2.0-or-later 7*069852d1SJackson Donaldson */ 8*069852d1SJackson Donaldson 9*069852d1SJackson Donaldson #include "qemu/osdep.h" 10*069852d1SJackson Donaldson #include "qemu/log.h" 11*069852d1SJackson Donaldson #include "trace.h" 12*069852d1SJackson Donaldson #include "hw/irq.h" 13*069852d1SJackson Donaldson #include "migration/vmstate.h" 14*069852d1SJackson Donaldson #include "hw/misc/max78000_trng.h" 15*069852d1SJackson Donaldson #include "qemu/guest-random.h" 16*069852d1SJackson Donaldson 17*069852d1SJackson Donaldson static uint64_t max78000_trng_read(void *opaque, hwaddr addr, 18*069852d1SJackson Donaldson unsigned int size) 19*069852d1SJackson Donaldson { 20*069852d1SJackson Donaldson uint32_t data; 21*069852d1SJackson Donaldson 22*069852d1SJackson Donaldson Max78000TrngState *s = opaque; 23*069852d1SJackson Donaldson switch (addr) { 24*069852d1SJackson Donaldson case CTRL: 25*069852d1SJackson Donaldson return s->ctrl; 26*069852d1SJackson Donaldson 27*069852d1SJackson Donaldson case STATUS: 28*069852d1SJackson Donaldson return 1; 29*069852d1SJackson Donaldson 30*069852d1SJackson Donaldson case DATA: 31*069852d1SJackson Donaldson /* 32*069852d1SJackson Donaldson * When interrupts are enabled, reading random data should cause a 33*069852d1SJackson Donaldson * new interrupt to be generated; since there's always a random number 34*069852d1SJackson Donaldson * available, we could qemu_set_irq(s->irq, s->ctrl & RND_IE). Because 35*069852d1SJackson Donaldson * of how trng_write is set up, this is always a noop, so don't 36*069852d1SJackson Donaldson */ 37*069852d1SJackson Donaldson qemu_guest_getrandom_nofail(&data, sizeof(data)); 38*069852d1SJackson Donaldson return data; 39*069852d1SJackson Donaldson 40*069852d1SJackson Donaldson default: 41*069852d1SJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 42*069852d1SJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 43*069852d1SJackson Donaldson break; 44*069852d1SJackson Donaldson } 45*069852d1SJackson Donaldson return 0; 46*069852d1SJackson Donaldson } 47*069852d1SJackson Donaldson 48*069852d1SJackson Donaldson static void max78000_trng_write(void *opaque, hwaddr addr, 49*069852d1SJackson Donaldson uint64_t val64, unsigned int size) 50*069852d1SJackson Donaldson { 51*069852d1SJackson Donaldson Max78000TrngState *s = opaque; 52*069852d1SJackson Donaldson uint32_t val = val64; 53*069852d1SJackson Donaldson switch (addr) { 54*069852d1SJackson Donaldson case CTRL: 55*069852d1SJackson Donaldson /* TODO: implement AES keygen */ 56*069852d1SJackson Donaldson s->ctrl = val; 57*069852d1SJackson Donaldson 58*069852d1SJackson Donaldson /* 59*069852d1SJackson Donaldson * This device models random number generation as taking 0 time. 60*069852d1SJackson Donaldson * A new random number is always available, so the condition for the 61*069852d1SJackson Donaldson * RND interrupt is always fulfilled; we can just set irq to 1. 62*069852d1SJackson Donaldson */ 63*069852d1SJackson Donaldson if (val & RND_IE) { 64*069852d1SJackson Donaldson qemu_set_irq(s->irq, 1); 65*069852d1SJackson Donaldson } else{ 66*069852d1SJackson Donaldson qemu_set_irq(s->irq, 0); 67*069852d1SJackson Donaldson } 68*069852d1SJackson Donaldson break; 69*069852d1SJackson Donaldson 70*069852d1SJackson Donaldson default: 71*069852d1SJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 72*069852d1SJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 73*069852d1SJackson Donaldson break; 74*069852d1SJackson Donaldson } 75*069852d1SJackson Donaldson } 76*069852d1SJackson Donaldson 77*069852d1SJackson Donaldson static void max78000_trng_reset_hold(Object *obj, ResetType type) 78*069852d1SJackson Donaldson { 79*069852d1SJackson Donaldson Max78000TrngState *s = MAX78000_TRNG(obj); 80*069852d1SJackson Donaldson s->ctrl = 0; 81*069852d1SJackson Donaldson s->status = 0; 82*069852d1SJackson Donaldson s->data = 0; 83*069852d1SJackson Donaldson } 84*069852d1SJackson Donaldson 85*069852d1SJackson Donaldson static const MemoryRegionOps max78000_trng_ops = { 86*069852d1SJackson Donaldson .read = max78000_trng_read, 87*069852d1SJackson Donaldson .write = max78000_trng_write, 88*069852d1SJackson Donaldson .endianness = DEVICE_LITTLE_ENDIAN, 89*069852d1SJackson Donaldson .valid.min_access_size = 4, 90*069852d1SJackson Donaldson .valid.max_access_size = 4, 91*069852d1SJackson Donaldson }; 92*069852d1SJackson Donaldson 93*069852d1SJackson Donaldson static const VMStateDescription max78000_trng_vmstate = { 94*069852d1SJackson Donaldson .name = TYPE_MAX78000_TRNG, 95*069852d1SJackson Donaldson .version_id = 1, 96*069852d1SJackson Donaldson .minimum_version_id = 1, 97*069852d1SJackson Donaldson .fields = (const VMStateField[]) { 98*069852d1SJackson Donaldson VMSTATE_UINT32(ctrl, Max78000TrngState), 99*069852d1SJackson Donaldson VMSTATE_UINT32(status, Max78000TrngState), 100*069852d1SJackson Donaldson VMSTATE_UINT32(data, Max78000TrngState), 101*069852d1SJackson Donaldson VMSTATE_END_OF_LIST() 102*069852d1SJackson Donaldson } 103*069852d1SJackson Donaldson }; 104*069852d1SJackson Donaldson 105*069852d1SJackson Donaldson static void max78000_trng_init(Object *obj) 106*069852d1SJackson Donaldson { 107*069852d1SJackson Donaldson Max78000TrngState *s = MAX78000_TRNG(obj); 108*069852d1SJackson Donaldson sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 109*069852d1SJackson Donaldson 110*069852d1SJackson Donaldson memory_region_init_io(&s->mmio, obj, &max78000_trng_ops, s, 111*069852d1SJackson Donaldson TYPE_MAX78000_TRNG, 0x1000); 112*069852d1SJackson Donaldson sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 113*069852d1SJackson Donaldson 114*069852d1SJackson Donaldson } 115*069852d1SJackson Donaldson 116*069852d1SJackson Donaldson static void max78000_trng_class_init(ObjectClass *klass, const void *data) 117*069852d1SJackson Donaldson { 118*069852d1SJackson Donaldson ResettableClass *rc = RESETTABLE_CLASS(klass); 119*069852d1SJackson Donaldson DeviceClass *dc = DEVICE_CLASS(klass); 120*069852d1SJackson Donaldson 121*069852d1SJackson Donaldson rc->phases.hold = max78000_trng_reset_hold; 122*069852d1SJackson Donaldson dc->vmsd = &max78000_trng_vmstate; 123*069852d1SJackson Donaldson 124*069852d1SJackson Donaldson } 125*069852d1SJackson Donaldson 126*069852d1SJackson Donaldson static const TypeInfo max78000_trng_info = { 127*069852d1SJackson Donaldson .name = TYPE_MAX78000_TRNG, 128*069852d1SJackson Donaldson .parent = TYPE_SYS_BUS_DEVICE, 129*069852d1SJackson Donaldson .instance_size = sizeof(Max78000TrngState), 130*069852d1SJackson Donaldson .instance_init = max78000_trng_init, 131*069852d1SJackson Donaldson .class_init = max78000_trng_class_init, 132*069852d1SJackson Donaldson }; 133*069852d1SJackson Donaldson 134*069852d1SJackson Donaldson static void max78000_trng_register_types(void) 135*069852d1SJackson Donaldson { 136*069852d1SJackson Donaldson type_register_static(&max78000_trng_info); 137*069852d1SJackson Donaldson } 138*069852d1SJackson Donaldson 139*069852d1SJackson Donaldson type_init(max78000_trng_register_types) 140