1 /* 2 * VMApple Configuration Region 3 * 4 * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 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 12 #include "qemu/osdep.h" 13 #include "hw/vmapple/vmapple.h" 14 #include "hw/sysbus.h" 15 #include "qemu/log.h" 16 #include "qemu/module.h" 17 #include "qapi/error.h" 18 #include "net/net.h" 19 20 OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG) 21 22 #define VMAPPLE_CFG_SIZE 0x00010000 23 24 typedef struct VMAppleCfg { 25 uint32_t version; /* 0x000 */ 26 uint32_t nr_cpus; /* 0x004 */ 27 uint32_t unk1; /* 0x008 */ 28 uint32_t unk2; /* 0x00c */ 29 uint32_t unk3; /* 0x010 */ 30 uint32_t unk4; /* 0x014 */ 31 uint64_t ecid; /* 0x018 */ 32 uint64_t ram_size; /* 0x020 */ 33 uint32_t run_installer1; /* 0x028 */ 34 uint32_t unk5; /* 0x02c */ 35 uint32_t unk6; /* 0x030 */ 36 uint32_t run_installer2; /* 0x034 */ 37 uint32_t rnd; /* 0x038 */ 38 uint32_t unk7; /* 0x03c */ 39 MACAddr mac_en0; /* 0x040 */ 40 uint8_t pad1[2]; 41 MACAddr mac_en1; /* 0x048 */ 42 uint8_t pad2[2]; 43 MACAddr mac_wifi0; /* 0x050 */ 44 uint8_t pad3[2]; 45 MACAddr mac_bt0; /* 0x058 */ 46 uint8_t pad4[2]; 47 uint8_t reserved[0xa0]; /* 0x060 */ 48 uint32_t cpu_ids[0x80]; /* 0x100 */ 49 uint8_t scratch[0x200]; /* 0x180 */ 50 char serial[32]; /* 0x380 */ 51 char unk8[32]; /* 0x3a0 */ 52 char model[32]; /* 0x3c0 */ 53 uint8_t unk9[32]; /* 0x3e0 */ 54 uint32_t unk10; /* 0x400 */ 55 char soc_name[32]; /* 0x404 */ 56 } VMAppleCfg; 57 58 struct VMAppleCfgState { 59 SysBusDevice parent_obj; 60 VMAppleCfg cfg; 61 62 MemoryRegion mem; 63 char *serial; 64 char *model; 65 char *soc_name; 66 }; 67 68 static void vmapple_cfg_reset(Object *obj, ResetType type) 69 { 70 VMAppleCfgState *s = VMAPPLE_CFG(obj); 71 VMAppleCfg *cfg; 72 73 cfg = memory_region_get_ram_ptr(&s->mem); 74 memset(cfg, 0, VMAPPLE_CFG_SIZE); 75 *cfg = s->cfg; 76 } 77 78 static bool set_fixlen_property_or_error(char *restrict dst, 79 const char *restrict src, 80 size_t dst_size, Error **errp, 81 const char *property_name) 82 { 83 ERRP_GUARD(); 84 size_t len; 85 86 len = g_strlcpy(dst, src, dst_size); 87 if (len < dst_size) { /* len does not count nul terminator */ 88 return true; 89 } 90 91 error_setg(errp, "Provided value too long for property '%s'", property_name); 92 error_append_hint(errp, "length (%zu) exceeds maximum of %zu\n", 93 len, dst_size - 1); 94 return false; 95 } 96 97 #define set_fixlen_property_or_return(dst_array, src, errp, property_name) \ 98 do { \ 99 if (!set_fixlen_property_or_error((dst_array), (src), \ 100 ARRAY_SIZE(dst_array), \ 101 (errp), (property_name))) { \ 102 return; \ 103 } \ 104 } while (0) 105 106 static void vmapple_cfg_realize(DeviceState *dev, Error **errp) 107 { 108 VMAppleCfgState *s = VMAPPLE_CFG(dev); 109 uint32_t i; 110 111 if (!s->serial) { 112 s->serial = g_strdup("1234"); 113 } 114 if (!s->model) { 115 s->model = g_strdup("VM0001"); 116 } 117 if (!s->soc_name) { 118 s->soc_name = g_strdup("Apple M1 (Virtual)"); 119 } 120 121 set_fixlen_property_or_return(s->cfg.serial, s->serial, errp, "serial"); 122 set_fixlen_property_or_return(s->cfg.model, s->model, errp, "model"); 123 set_fixlen_property_or_return(s->cfg.soc_name, s->soc_name, errp, "soc_name"); 124 set_fixlen_property_or_return(s->cfg.unk8, "D/A", errp, "unk8"); 125 s->cfg.version = 2; 126 s->cfg.unk1 = 1; 127 s->cfg.unk2 = 1; 128 s->cfg.unk3 = 0x20; 129 s->cfg.unk4 = 0; 130 s->cfg.unk5 = 1; 131 s->cfg.unk6 = 1; 132 s->cfg.unk7 = 0; 133 s->cfg.unk10 = 1; 134 135 if (s->cfg.nr_cpus > ARRAY_SIZE(s->cfg.cpu_ids)) { 136 error_setg(errp, 137 "Failed to create %u CPUs, vmapple machine supports %zu max", 138 s->cfg.nr_cpus, ARRAY_SIZE(s->cfg.cpu_ids)); 139 return; 140 } 141 for (i = 0; i < s->cfg.nr_cpus; i++) { 142 s->cfg.cpu_ids[i] = i; 143 } 144 } 145 146 static void vmapple_cfg_init(Object *obj) 147 { 148 VMAppleCfgState *s = VMAPPLE_CFG(obj); 149 150 memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZE, 151 &error_fatal); 152 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem); 153 } 154 155 static const Property vmapple_cfg_properties[] = { 156 DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1), 157 DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0), 158 DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0), 159 DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installer1, 0), 160 DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installer2, 0), 161 DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0), 162 DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0), 163 DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1), 164 DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0), 165 DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0), 166 DEFINE_PROP_STRING("serial", VMAppleCfgState, serial), 167 DEFINE_PROP_STRING("model", VMAppleCfgState, model), 168 DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name), 169 }; 170 171 static void vmapple_cfg_class_init(ObjectClass *klass, void *data) 172 { 173 DeviceClass *dc = DEVICE_CLASS(klass); 174 ResettableClass *rc = RESETTABLE_CLASS(klass); 175 176 dc->realize = vmapple_cfg_realize; 177 dc->desc = "VMApple Configuration Region"; 178 device_class_set_props(dc, vmapple_cfg_properties); 179 rc->phases.hold = vmapple_cfg_reset; 180 } 181 182 static const TypeInfo vmapple_cfg_info = { 183 .name = TYPE_VMAPPLE_CFG, 184 .parent = TYPE_SYS_BUS_DEVICE, 185 .instance_size = sizeof(VMAppleCfgState), 186 .instance_init = vmapple_cfg_init, 187 .class_init = vmapple_cfg_class_init, 188 }; 189 190 static void vmapple_cfg_register_types(void) 191 { 192 type_register_static(&vmapple_cfg_info); 193 } 194 195 type_init(vmapple_cfg_register_types) 196