1 /* 2 * HPPA interrupt helper routines 3 * 4 * Copyright (c) 2017 Richard Henderson 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "migration/cpu.h" 23 24 25 static int get_psw(QEMUFile *f, void *opaque, size_t size, 26 const VMStateField *field) 27 { 28 CPUHPPAState *env = opaque; 29 cpu_hppa_put_psw(env, qemu_get_be64(f)); 30 return 0; 31 } 32 33 static int put_psw(QEMUFile *f, void *opaque, size_t size, 34 const VMStateField *field, JSONWriter *vmdesc) 35 { 36 CPUHPPAState *env = opaque; 37 qemu_put_be64(f, cpu_hppa_get_psw(env)); 38 return 0; 39 } 40 41 static const VMStateInfo vmstate_psw = { 42 .name = "psw", 43 .get = get_psw, 44 .put = put_psw, 45 }; 46 47 static int get_tlb(QEMUFile *f, void *opaque, size_t size, 48 const VMStateField *field) 49 { 50 HPPATLBEntry *ent = opaque; 51 uint64_t val; 52 53 ent->itree.start = qemu_get_be64(f); 54 ent->itree.last = qemu_get_be64(f); 55 ent->pa = qemu_get_be64(f); 56 val = qemu_get_be64(f); 57 58 if (val) { 59 ent->t = extract64(val, 61, 1); 60 ent->d = extract64(val, 60, 1); 61 ent->b = extract64(val, 59, 1); 62 ent->ar_type = extract64(val, 56, 3); 63 ent->ar_pl1 = extract64(val, 54, 2); 64 ent->ar_pl2 = extract64(val, 52, 2); 65 ent->u = extract64(val, 51, 1); 66 /* o = bit 50 */ 67 /* p = bit 49 */ 68 ent->access_id = extract64(val, 1, 31); 69 ent->entry_valid = 1; 70 } 71 return 0; 72 } 73 74 static int put_tlb(QEMUFile *f, void *opaque, size_t size, 75 const VMStateField *field, JSONWriter *vmdesc) 76 { 77 HPPATLBEntry *ent = opaque; 78 uint64_t val = 0; 79 80 if (ent->entry_valid) { 81 val = 1; 82 val = deposit64(val, 61, 1, ent->t); 83 val = deposit64(val, 60, 1, ent->d); 84 val = deposit64(val, 59, 1, ent->b); 85 val = deposit64(val, 56, 3, ent->ar_type); 86 val = deposit64(val, 54, 2, ent->ar_pl1); 87 val = deposit64(val, 52, 2, ent->ar_pl2); 88 val = deposit64(val, 51, 1, ent->u); 89 /* o = bit 50 */ 90 /* p = bit 49 */ 91 val = deposit64(val, 1, 31, ent->access_id); 92 } 93 94 qemu_put_be64(f, ent->itree.start); 95 qemu_put_be64(f, ent->itree.last); 96 qemu_put_be64(f, ent->pa); 97 qemu_put_be64(f, val); 98 return 0; 99 } 100 101 static const VMStateInfo vmstate_tlb_entry = { 102 .name = "tlb entry", 103 .get = get_tlb, 104 .put = put_tlb, 105 }; 106 107 static int tlb_pre_load(void *opaque) 108 { 109 CPUHPPAState *env = opaque; 110 111 /* 112 * Zap the entire tlb, on-the-side data structures and all. 113 * Each tlb entry will have data re-filled by put_tlb. 114 */ 115 memset(env->tlb, 0, sizeof(env->tlb)); 116 memset(&env->tlb_root, 0, sizeof(env->tlb_root)); 117 env->tlb_unused = NULL; 118 env->tlb_partial = NULL; 119 120 return 0; 121 } 122 123 static int tlb_post_load(void *opaque, int version_id) 124 { 125 CPUHPPAState *env = opaque; 126 uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env); 127 HPPATLBEntry **unused = &env->tlb_unused; 128 HPPATLBEntry *partial = NULL; 129 130 /* 131 * Re-create the interval tree from the valid entries. 132 * Truly invalid entries should have start == end == 0. 133 * Otherwise it should be the in-flight tlb_partial entry. 134 */ 135 for (uint32_t i = 0; i < ARRAY_SIZE(env->tlb); ++i) { 136 HPPATLBEntry *e = &env->tlb[i]; 137 138 if (e->entry_valid) { 139 interval_tree_insert(&e->itree, &env->tlb_root); 140 } else if (i < btlb_entries) { 141 /* btlb not in unused list */ 142 } else if (partial == NULL && e->itree.start < e->itree.last) { 143 partial = e; 144 } else { 145 *unused = e; 146 unused = &e->unused_next; 147 } 148 } 149 env->tlb_partial = partial; 150 *unused = NULL; 151 152 return 0; 153 } 154 155 static const VMStateField vmstate_tlb_fields[] = { 156 VMSTATE_ARRAY(tlb, CPUHPPAState, 157 ARRAY_SIZE(((CPUHPPAState *)0)->tlb), 158 0, vmstate_tlb_entry, HPPATLBEntry), 159 VMSTATE_UINT32(tlb_last, CPUHPPAState), 160 VMSTATE_END_OF_LIST() 161 }; 162 163 static const VMStateDescription vmstate_tlb = { 164 .name = "env/tlb", 165 .version_id = 1, 166 .minimum_version_id = 1, 167 .fields = vmstate_tlb_fields, 168 .pre_load = tlb_pre_load, 169 .post_load = tlb_post_load, 170 }; 171 172 static const VMStateField vmstate_env_fields[] = { 173 VMSTATE_UINT64_ARRAY(gr, CPUHPPAState, 32), 174 VMSTATE_UINT64_ARRAY(fr, CPUHPPAState, 32), 175 VMSTATE_UINT64_ARRAY(sr, CPUHPPAState, 8), 176 VMSTATE_UINT64_ARRAY(cr, CPUHPPAState, 32), 177 VMSTATE_UINT64_ARRAY(cr_back, CPUHPPAState, 2), 178 VMSTATE_UINT64_ARRAY(shadow, CPUHPPAState, 7), 179 180 /* Save the architecture value of the psw, not the internally 181 expanded version. Since this architecture value does not 182 exist in memory to be stored, this requires a but of hoop 183 jumping. We want OFFSET=0 so that we effectively pass ENV 184 to the helper functions, and we need to fill in the name by 185 hand since there's no field of that name. */ 186 { 187 .name = "psw", 188 .version_id = 0, 189 .size = sizeof(uint64_t), 190 .info = &vmstate_psw, 191 .flags = VMS_SINGLE, 192 .offset = 0 193 }, 194 195 VMSTATE_UINT64(iaoq_f, CPUHPPAState), 196 VMSTATE_UINT64(iaoq_b, CPUHPPAState), 197 VMSTATE_UINT64(iasq_f, CPUHPPAState), 198 VMSTATE_UINT64(iasq_b, CPUHPPAState), 199 200 VMSTATE_UINT32(fr0_shadow, CPUHPPAState), 201 VMSTATE_END_OF_LIST() 202 }; 203 204 static const VMStateDescription *vmstate_env_subsections[] = { 205 &vmstate_tlb, 206 NULL 207 }; 208 209 static const VMStateDescription vmstate_env = { 210 .name = "env", 211 .version_id = 3, 212 .minimum_version_id = 3, 213 .fields = vmstate_env_fields, 214 .subsections = vmstate_env_subsections, 215 }; 216 217 static const VMStateField vmstate_cpu_fields[] = { 218 VMSTATE_CPU(), 219 VMSTATE_STRUCT(env, HPPACPU, 1, vmstate_env, CPUHPPAState), 220 VMSTATE_END_OF_LIST() 221 }; 222 223 const VMStateDescription vmstate_hppa_cpu = { 224 .name = "cpu", 225 .version_id = 1, 226 .minimum_version_id = 1, 227 .fields = vmstate_cpu_fields, 228 }; 229