xref: /openbmc/qemu/target/hppa/machine.c (revision 3161f9f4)
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