Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / res_vcpu.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: res_vcpu.c
5*
6* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
7*
8* - Do no alter or remove copyright notices
9*
10* - Redistribution and use of this software in source and binary forms, with
11* or without modification, are permitted provided that the following
12* conditions are met:
13*
14* - Redistribution of source code must retain the above copyright notice,
15* this list of conditions and the following disclaimer.
16*
17* - Redistribution in binary form must reproduce the above copyright notice,
18* this list of conditions and the following disclaimer in the
19* documentation and/or other materials provided with the distribution.
20*
21* Neither the name of Sun Microsystems, Inc. or the names of contributors
22* may be used to endorse or promote products derived from this software
23* without specific prior written permission.
24*
25* This software is provided "AS IS," without a warranty of any kind.
26* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
27* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
28* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
29* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
30* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
31* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
32* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
33* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
34* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
35* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
36* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*
38* You acknowledge that this software is not designed, licensed or
39* intended for use in the design, construction, operation or maintenance of
40* any nuclear facility.
41*
42* ========== Copyright Header End ============================================
43*/
44/*
45 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
46 * Use is subject to license terms.
47 */
48
49#pragma ident "@(#)res_vcpu.c 1.8 07/07/09 SMI"
50
51#include <stdarg.h>
52#include <sys/htypes.h>
53#include <hypervisor.h>
54#include <traps.h>
55#include <cache.h>
56#include <mmu.h>
57#include <sun4v/asi.h>
58#include <sun4v/errs_defs.h>
59#include <vdev_intr.h>
60#include <ncs.h>
61#include <cyclic.h>
62#include <support.h>
63#include <strand.h>
64#include <vcpu.h>
65#include <guest.h>
66#include <pcie.h>
67#include <vdev_ops.h>
68#include <fpga.h>
69#include <ldc.h>
70#include <config.h>
71#include <offsets.h>
72#include <hvctl.h>
73#include <md.h>
74#include <abort.h>
75#include <hypervisor.h>
76#include <proto.h>
77
78
79/*
80 * (re)-configuration code to handle HV vcpu resources
81 */
82
83static hvctl_status_t
84res_vcpu_parse_1(bin_md_t *mdp, md_element_t *cpunodep,
85 hvctl_res_error_t *fail_codep, int *fail_res_idp);
86static void res_vcpu_commit_config(vcpu_t *vcpup);
87static void res_vcpu_commit_unconfig(vcpu_t *vcpup);
88
89
90/*
91 * vcpu support functions.
92 */
93void
94init_vcpu(int i)
95{
96 vcpu_t *vp;
97
98 vp = (vcpu_t *)config.vcpus;
99 vp = &(vp[i]);
100
101 c_bzero(vp, sizeof (*vp));
102
103 vp->res_id = i;
104 vp->status = CPU_STATE_UNCONFIGURED;
105}
106
107
108void
109res_vcpu_prep()
110{
111 vcpu_t *vp;
112 int i;
113
114 vp = config.vcpus;
115
116 for (i = 0; i < NVCPUS; i++, vp++) {
117 vp->pip.res.flags = (vp->status == CPU_STATE_UNCONFIGURED) ?
118 RESF_Noop : RESF_Unconfig;
119 }
120}
121
122
123hvctl_status_t
124res_vcpu_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep,
125 md_element_t **failnodepp, int *fail_res_idp)
126{
127 md_element_t *mdep;
128 uint64_t arc_token;
129 uint64_t node_token;
130 md_element_t *cpunodep;
131
132 mdp = (bin_md_t *)config.parse_hvmd;
133
134 mdep = md_find_node(mdp, NULL, MDNAME(cpus));
135 if (mdep == NULL) {
136 DBG(c_printf("Missing cpus node in HVMD\n"));
137 *failnodepp = NULL;
138 *fail_res_idp = 0;
139 return (HVctl_st_badmd);
140 }
141
142 arc_token = MDARC(MDNAME(fwd));
143 node_token = MDNODE(MDNAME(cpu));
144
145 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
146 arc_token, node_token, &cpunodep))) {
147 hvctl_status_t status;
148 status = res_vcpu_parse_1(mdp, cpunodep,
149 fail_codep, fail_res_idp);
150 if (status != HVctl_st_ok) {
151 *failnodepp = cpunodep;
152 return (status);
153 }
154 }
155 return (HVctl_st_ok);
156}
157
158
159hvctl_status_t
160res_vcpu_parse_1(bin_md_t *mdp, md_element_t *cpunodep,
161 hvctl_res_error_t *fail_codep, int *fail_res_idp)
162{
163 uint64_t strand_id, res_id, vid, gid, parttag;
164 vcpu_t *vcpup;
165 md_element_t *guestnodep;
166
167 DBGVCPU(md_dump_node(mdp, cpunodep));
168
169 if (!md_node_get_val(mdp, cpunodep, MDNAME(resource_id), &res_id)) {
170 DBGVCPU(c_printf("Missing resource_id in cpu node\n"));
171 *fail_codep = HVctl_e_vcpu_missing_id;
172 *fail_res_idp = 0;
173 goto fail;
174 }
175 if (res_id >= NVCPUS) {
176 DBGVCPU(c_printf("Invalid resource_id in cpu node\n"));
177 *fail_codep = HVctl_e_vcpu_invalid_id;
178 *fail_res_idp = 0;
179 goto fail;
180 }
181
182 *fail_res_idp = res_id;
183
184 DBGVCPU(c_printf("res_vcpu_parse_1(0x%x)\n", res_id));
185
186 if (!md_node_get_val(mdp, cpunodep, MDNAME(pid), &strand_id)) {
187 DBGVCPU(c_printf("Missing PID in cpu node\n"));
188 *fail_codep = HVctl_e_vcpu_missing_strandid;
189 goto fail;
190 }
191 if (strand_id >= NSTRANDS) {
192 DBGVCPU(c_printf("Invalid PID in cpu node\n"));
193 *fail_codep = HVctl_e_vcpu_invalid_strandid;
194 goto fail;
195 }
196
197 /* Get virtual ID within guest */
198 if (!md_node_get_val(mdp, cpunodep, MDNAME(vid), &vid)) {
199 DBGVCPU(c_printf("Missing VID in cpu node\n"));
200 *fail_codep = HVctl_e_vcpu_missing_vid;
201 goto fail;
202 }
203
204 if (NULL == md_find_node_by_arc(mdp, cpunodep, MDARC(MDNAME(back)),
205 MDNODE(MDNAME(guest)), &guestnodep)) {
206 DBGVCPU(c_printf(
207 "Missing back arc to guest node in cpu node\n"));
208 *fail_codep = HVctl_e_vcpu_missing_guest;
209 goto fail;
210 }
211
212 if (!md_node_get_val(mdp, guestnodep, MDNAME(resource_id), &gid)) {
213 DBGVCPU(c_printf("Missing resource_id in guest node\n"));
214 *fail_codep = HVctl_e_guest_missing_id;
215 goto fail;
216 }
217
218 if (gid >= NGUESTS) {
219 DBGVCPU(c_printf("Invalid resource_id in guest node\n"));
220 *fail_codep = HVctl_e_guest_invalid_id;
221 goto fail;
222 }
223
224
225 /* Get partid tag for this cpu */
226 if (!md_node_get_val(mdp, cpunodep, MDNAME(parttag), &parttag)) {
227 DBGVCPU(c_printf("WARNING: Missing parttag in cpu node - "
228 "using guest id 0x%x\n", gid));
229 parttag = gid; /* use guest ID if none given */
230 }
231
232
233 DBGVCPU(c_printf("Virtual cpu 0x%x in guest 0x%x (vid 0x%x)\n",
234 res_id, gid, vid));
235
236
237 /*
238 * Now determine the delta - if relevent...
239 */
240 vcpup = config.vcpus;
241 vcpup = &(vcpup[res_id]);
242
243 vcpup->pip.strand_id = strand_id;
244 vcpup->pip.vid = vid;
245 vcpup->pip.guestid = gid;
246 vcpup->pip.parttag = parttag;
247
248 ASSERT(vcpup->status != CPU_STATE_INVALID);
249
250 /*
251 * We can configure an unconfigured CPU.
252 * Cannot (yet) support the dynamic re-binding of
253 * a configured / running cpu.
254 */
255 DBGVCPU(c_printf("\t\tCurrent cpu status = 0x%x\n", vcpup->status));
256
257 if (vcpup->status == CPU_STATE_UNCONFIGURED) {
258 DBGVCPU(c_printf("\t\tElected to config vcpu\n"));
259 vcpup->pip.res.flags = RESF_Config;
260 } else {
261 if (vcpup->strand->id == strand_id &&
262 vcpup->vid == vid &&
263 vcpup->guest->guestid == gid &&
264 vcpup->parttag == parttag) {
265 DBGVCPU(c_printf("\t\tElected to ignore vcpu\n"));
266 vcpup->pip.res.flags = RESF_Noop;
267 } else {
268 DBGVCPU(c_printf("\t\tFailed MD update - no "
269 "rebind live\n"));
270 *fail_codep = HVctl_e_vcpu_rebind_na;
271 goto fail;
272 }
273 }
274
275 return (HVctl_st_ok);
276fail:;
277 return (HVctl_st_badmd);
278}
279
280
281hvctl_status_t
282res_vcpu_postparse(hvctl_res_error_t *res_error, int *fail_res_id)
283{
284 return (HVctl_st_ok);
285}
286
287
288void
289res_vcpu_commit(int flag)
290{
291 vcpu_t *vp;
292 int i;
293
294 vp = config.vcpus;
295
296 for (i = 0; i < NVCPUS; i++, vp++) {
297 /* if not this ops turn move on */
298 DBGVCPU(c_printf("res_vcpu_commit: vcpuid 0x%x : state 0x%x : "
299 "flags 0x%x - opflag 0x%x\n",
300 vp->vid, vp->status, vp->pip.res.flags, flag));
301
302 if (vp->pip.res.flags != flag) continue;
303
304 switch (vp->pip.res.flags) {
305 case RESF_Noop:
306 DBGVCPU(c_printf("vcpu 0x%x : noop\n", i));
307 break;
308 case RESF_Unconfig:
309 DBGVCPU(c_printf("vcpu 0x%x : unconfig\n", i));
310 res_vcpu_commit_unconfig(vp);
311 break;
312 case RESF_Config:
313 DBGVCPU(c_printf("vcpu 0x%x : config\n", i));
314 res_vcpu_commit_config(vp);
315 break;
316 case RESF_Rebind:
317 DBGVCPU(c_printf("vcpu 0x%x : rebind\n", i));
318 ASSERT(0); /* not supported */
319 break;
320 case RESF_Modify:
321 DBGVCPU(c_printf("vcpu 0x%x : modify\n", i));
322 ASSERT(0); /* not supported */
323 break;
324 default:
325 ASSERT(0);
326 }
327
328 vp->pip.res.flags = RESF_Noop; /* cleanup */
329 }
330}
331
332
333void
334res_vcpu_commit_config(vcpu_t *vcpup)
335{
336 strand_t *strandp;
337 guest_t *guestp;
338
339 DBGVCPU(c_printf("res_vcpu_commit_config\n"));
340
341 /*
342 * Assign the vcpu its carrier strand.
343 * Note: this does not schedule the cpu.
344 */
345 DBGVCPU(c_printf("\tBinding vcpu (res_id = 0x%x) to strand 0x%x as "
346 "vid 0x%x in guest 0x%x\n", vcpup->res_id,
347 vcpup->pip.strand_id, vcpup->pip.vid, vcpup->pip.guestid));
348
349 strandp = config.strands;
350 strandp = &(strandp[vcpup->pip.strand_id]);
351
352 vcpup->strand = strandp;
353 vcpup->strand_slot = 0; /* FIXME fixed for the moment */
354
355 vcpup->vid = vcpup->pip.vid;
356 vcpup->parttag = vcpup->pip.parttag;
357
358 guestp = config.guests;
359 guestp = &(guestp[vcpup->pip.guestid]);
360 ASSERT(guestp->guestid == vcpup->pip.guestid);
361 vcpup->guest = guestp;
362
363 ASSERT(guestp->vcpus[vcpup->vid] == NULL);
364 guestp->vcpus[vcpup->vid] = vcpup;
365
366#ifdef CONFIG_CRYPTO
367 /* gets setup later if crypto run */
368 vcpup->maup = NULL;
369 vcpup->cwqp = NULL;
370#endif
371 /*
372 * Initialise the remainder of the vCPU struct
373 */
374 vcpup->mmu_area = 0LL;
375 vcpup->mmu_area_ra = 0LL;
376 vcpup->root = &config; /* FIXME: need this ? */
377
378 /*
379 * Assume guest rtba starts at the base of memory
380 * until the guest reconfigures this. The entry point
381 * is computed from this.
382 */
383 vcpup->rtba = guestp->real_base;
384
385 /* Assert the legacy entry point had better be the same */
386 ASSERT(guestp->entry == guestp->real_base);
387
388 DBGVCPU(c_printf("Virtual cpu 0x%x in guest 0x%x (vid 0x%x) "
389 "entry @ 0x%x rtba @ 0x%x\n",
390 vcpup->res_id, vcpup->guest->guestid, vcpup->vid,
391 guestp->entry, vcpup->rtba));
392
393
394 /*
395 * Now for the basic sun4v cpu state.
396 */
397
398 /*
399 * Guests entry point should be at the power on
400 * vector of the rtba - at least for the boot cpu.
401 */
402 vcpup->start_pc = vcpup->rtba + TT_POR*TRAPTABLE_ENTRY_SIZE;
403
404 reset_vcpu_state(vcpup);
405
406 /*
407 * check to see if the strand the VCPU is bound
408 * to is in active state, if not mark the VCPU
409 * in error
410 */
411 if (config.strand_active & (1LL<<vcpup->pip.strand_id)) {
412 vcpup->status = CPU_STATE_STOPPED;
413 } else {
414 vcpup->status = CPU_STATE_ERROR;
415 }
416
417 /* initialize vcpu utilization information */
418 c_bzero(&vcpup->util, sizeof (vcpup->util));
419}
420
421
422void
423res_vcpu_commit_unconfig(vcpu_t *vcpup)
424{
425 ASSERT(vcpup->status == CPU_STATE_STOPPED ||
426 vcpup->status == CPU_STATE_ERROR);
427
428 ASSERT(vcpup->guest != NULL);
429 ASSERT(vcpup->strand != NULL);
430
431 /* Clean up actions */
432 vcpup->guest->vcpus[vcpup->vid] = NULL;
433
434 vcpup->guest = NULL;
435 vcpup->strand = NULL;
436#ifdef CONFIG_CRYPTO
437 vcpup->maup = NULL;
438 vcpup->cwqp = NULL;
439#endif
440 /*
441 * stuff like cyclics should already have been turned off
442 * when we stop the cpu
443 */
444
445 /* FIXME: need to cleanup */
446 vcpup->status = CPU_STATE_UNCONFIGURED;
447}