Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: res_guest.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_guest.c 1.6 07/06/07 SMI" | |
50 | ||
51 | #include <stdarg.h> | |
52 | #include <sys/htypes.h> | |
53 | #include <traps.h> | |
54 | #include <cache.h> | |
55 | #include <mmu.h> | |
56 | #include <sun4v/asi.h> | |
57 | #include <vdev_intr.h> | |
58 | #include <ncs.h> | |
59 | #include <cyclic.h> | |
60 | #include <support.h> | |
61 | #include <strand.h> | |
62 | #include <vcpu.h> | |
63 | #include <guest.h> | |
64 | #include <pcie.h> | |
65 | #include <vdev_ops.h> | |
66 | #include <fpga.h> | |
67 | #include <ldc.h> | |
68 | #include <config.h> | |
69 | #include <offsets.h> | |
70 | #include <hvctl.h> | |
71 | #include <md.h> | |
72 | #include <abort.h> | |
73 | #include <hypervisor.h> | |
74 | #include <proto.h> | |
75 | ||
76 | /* | |
77 | * (re)-configuration code to handle HV guest resources | |
78 | */ | |
79 | ||
80 | static hvctl_status_t res_guest_parse_1(bin_md_t *mdp, md_element_t *guestnodep, | |
81 | hvctl_res_error_t *fail_codep, int *fail_res_idp); | |
82 | ||
83 | static void res_guest_commit_config(guest_t *guestp); | |
84 | static void res_guest_commit_unconfig(guest_t *guestp); | |
85 | static void res_guest_commit_modify(guest_t *guestp); | |
86 | ||
87 | ||
88 | void config_a_guest_device_vino(guest_t *guestp, int ino, uint8_t type); | |
89 | void unconfig_a_guest_device_vino(guest_t *guestp, int ino, uint8_t type); | |
90 | void config_guest_virtual_device(guest_t *guestp, uint64_t cfg_handle); | |
91 | void unconfig_guest_virtual_device(guest_t *guestp); | |
92 | void config_guest_channel_device(guest_t *guestp, uint64_t cfg_handle); | |
93 | void unconfig_guest_channel_device(guest_t *guestp); | |
94 | ||
95 | void | |
96 | init_guest(int i) | |
97 | { | |
98 | guest_t *gp; | |
99 | hvctl_msg_t *asmsg; | |
100 | int j; | |
101 | ||
102 | gp = (guest_t *)config.guests; | |
103 | gp = &(gp[i]); | |
104 | ||
105 | /* clear out everything ! */ | |
106 | c_bzero(gp, sizeof (*gp)); | |
107 | ||
108 | gp->guestid = i; | |
109 | gp->state = GUEST_STATE_UNCONFIGURED; | |
110 | ||
111 | /* FIXME: remove the configp pointer */ | |
112 | gp->configp = &config; | |
113 | ||
114 | gp->pip.vdev_cfghandle = INVALID_CFGHANDLE; | |
115 | gp->pip.cdev_cfghandle = INVALID_CFGHANDLE; | |
116 | ||
117 | for (j = 0; j < NUM_RA2PA_SEGMENTS; j++) { | |
118 | init_ra2pa_segment(&(gp->ra2pa_segment[j])); | |
119 | } | |
120 | ||
121 | asmsg = (hvctl_msg_t *)gp->async_buf; | |
122 | asmsg->hdr.op = HVctl_op_new_res_stat; | |
123 | ||
124 | /* Everything else gets whacked when we (re)config the guest */ | |
125 | } | |
126 | ||
127 | ||
128 | ||
129 | ||
130 | /* | |
131 | * Guest MD support functions. | |
132 | */ | |
133 | void | |
134 | res_guest_prep() | |
135 | { | |
136 | guest_t *gp; | |
137 | int i; | |
138 | ||
139 | gp = config.guests; | |
140 | ||
141 | for (i = 0; i < NGUESTS; i++, gp++) { | |
142 | gp->pip.res.flags = (gp->state == GUEST_STATE_UNCONFIGURED) ? | |
143 | RESF_Noop : RESF_Unconfig; | |
144 | } | |
145 | } | |
146 | ||
147 | ||
148 | hvctl_status_t | |
149 | res_guest_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep, | |
150 | md_element_t **failnodepp, int *fail_res_idp) | |
151 | { | |
152 | md_element_t *mdep; | |
153 | uint64_t arc_token; | |
154 | uint64_t node_token; | |
155 | md_element_t *guest_nodep; | |
156 | ||
157 | mdp = (bin_md_t *)config.parse_hvmd; | |
158 | ||
159 | DBG(c_printf("\nGuest configuration:\n")); | |
160 | ||
161 | mdep = md_find_node(mdp, NULL, MDNAME(guests)); | |
162 | if (mdep == NULL) { | |
163 | DBG(c_printf("Missing guests node in HVMD\n")); | |
164 | *failnodepp = NULL; | |
165 | *fail_res_idp = 0; | |
166 | return (HVctl_st_badmd); | |
167 | } | |
168 | ||
169 | arc_token = MDARC(MDNAME(fwd)); | |
170 | node_token = MDNODE(MDNAME(guest)); | |
171 | ||
172 | while (NULL != (mdep = md_find_node_by_arc(mdp, mdep, arc_token, | |
173 | node_token, &guest_nodep))) { | |
174 | hvctl_status_t status; | |
175 | status = res_guest_parse_1(mdp, guest_nodep, fail_codep, | |
176 | fail_res_idp); | |
177 | if (status != HVctl_st_ok) { | |
178 | *failnodepp = guest_nodep; | |
179 | return (status); | |
180 | } | |
181 | } | |
182 | return (HVctl_st_ok); | |
183 | } | |
184 | ||
185 | hvctl_status_t | |
186 | res_guest_parse_1(bin_md_t *mdp, md_element_t *guest_nodep, | |
187 | hvctl_res_error_t *fail_codep, int *fail_res_idp) | |
188 | { | |
189 | uint64_t resource_id, unbind, cfg_handle, base_memsize; | |
190 | uint64_t arc_token, node_token; | |
191 | guest_t *guestp; | |
192 | md_element_t *mblock_nodep, *mdep, *base_mblock; | |
193 | md_element_t *devices_nodep; | |
194 | ||
195 | DBG(c_printf("res_guest_parse_1\n")); | |
196 | DBG(md_dump_node(mdp, guest_nodep)); | |
197 | ||
198 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(resource_id), | |
199 | &resource_id)) { | |
200 | DBG(c_printf("Missing resource_id in guest node\n")); | |
201 | *fail_codep = HVctl_e_guest_missing_id; | |
202 | *fail_res_idp = 0; | |
203 | return (HVctl_st_badmd); | |
204 | } | |
205 | if (resource_id >= NGUESTS) { | |
206 | DBG(c_printf("Invalid resource_id in guest node\n")); | |
207 | *fail_codep = HVctl_e_guest_invalid_id; | |
208 | *fail_res_idp = 0; | |
209 | return (HVctl_st_badmd); | |
210 | } | |
211 | ||
212 | guestp = config.guests; | |
213 | guestp = &(guestp[resource_id]); | |
214 | ||
215 | DBG(c_printf("Guest 0x%x @ 0x%x\n", resource_id, (uint64_t)guestp)); | |
216 | ||
217 | *fail_res_idp = resource_id; | |
218 | ||
219 | /* | |
220 | * If guest is being unbound check that it is stopped. | |
221 | */ | |
222 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(unbind), &unbind)) | |
223 | unbind = 0; | |
224 | if (unbind != 0) { | |
225 | if (guestp->state != GUEST_STATE_STOPPED) { | |
226 | *fail_codep = HVctl_e_guest_active; | |
227 | return (HVctl_st_eillegal); | |
228 | } | |
229 | } | |
230 | ||
231 | /* | |
232 | * Now fill in basic properties for this guest ... | |
233 | * | |
234 | * FIXME: These should be available is the guest is | |
235 | * live yes ? | |
236 | */ | |
237 | ||
238 | #define GET_PROPERTY(_g_val, _md_name) \ | |
239 | do { \ | |
240 | uint64_t _x; \ | |
241 | if (!md_node_get_val(mdp, guest_nodep, \ | |
242 | MDNAME(_md_name), &_x)) { \ | |
243 | DBG(c_printf("Missing "#_md_name" in " \ | |
244 | "guest node\n")); \ | |
245 | goto missing_prop; \ | |
246 | } \ | |
247 | _g_val = _x; \ | |
248 | } while (0) | |
249 | ||
250 | /* A guest can't change ID, so just push it in */ | |
251 | GET_PROPERTY(guestp->guestid, resource_id); | |
252 | GET_PROPERTY(guestp->pip.rom_base, rombase); | |
253 | GET_PROPERTY(guestp->pip.rom_size, romsize); | |
254 | ||
255 | GET_PROPERTY(guestp->pip.md_pa, mdpa); | |
256 | ||
257 | #ifdef CONFIG_CN_UART | |
258 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(uartbase), | |
259 | &guestp->pip.uartbase)) { | |
260 | guestp->pip.uartbase = -1LL; | |
261 | } | |
262 | #endif | |
263 | ||
264 | #ifdef CONFIG_DISK | |
265 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(diskpa), | |
266 | &guestp->pip.diskpa)) { | |
267 | guestp->pip.diskpa = -1LL; | |
268 | } | |
269 | #endif | |
270 | ||
271 | /* | |
272 | * Check for a reset-reason property | |
273 | * | |
274 | * FIXME: How sensible is this in an LDoms world? | |
275 | * This is fine unless master start gets called somehow as | |
276 | * part of the guest reconfig - so dont do that unless | |
277 | * you really mean it ! | |
278 | * | |
279 | * FIXME: Again - why re-do if guest configured already | |
280 | */ | |
281 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(reset_reason), | |
282 | &guestp->pip.reset_reason)) { | |
283 | guestp->pip.reset_reason = RESET_REASON_POR; | |
284 | } | |
285 | ||
286 | /* | |
287 | * Determine guest realbase. | |
288 | */ | |
289 | guestp->pip.real_base = UINT64_MAX; | |
290 | guestp->pip.real_limit = 0; | |
291 | guestp->pip.mem_offset = 0; | |
292 | ||
293 | arc_token = MDARC(MDNAME(fwd)); | |
294 | node_token = MDNODE(MDNAME(mblock)); | |
295 | ||
296 | base_mblock = NULL; | |
297 | mdep = guest_nodep; | |
298 | ||
299 | while (NULL != (mdep = md_find_node_by_arc(mdp, mdep, | |
300 | arc_token, node_token, &mblock_nodep))) { | |
301 | uint64_t realbase, membase; | |
302 | if (!md_node_get_val(mdp, mblock_nodep, MDNAME(realbase), | |
303 | &realbase)) { | |
304 | DBG(c_printf("Missing realbase in mblock node\n")); | |
305 | goto missing_prop; | |
306 | } | |
307 | ||
308 | /* | |
309 | * Initialise guest real_base, real_limit and mem_offset | |
310 | * Note: real_limit/mem_offset are required for N2 MMu HWTW | |
311 | * FIXME: real_limit will not work for segmented memory | |
312 | */ | |
313 | if (realbase < guestp->pip.real_base) { | |
314 | guestp->pip.real_base = realbase; | |
315 | base_mblock = mblock_nodep; | |
316 | if (!md_node_get_val(mdp, mblock_nodep, MDNAME(membase), | |
317 | &membase)) { | |
318 | membase = guestp->pip.real_base; | |
319 | } | |
320 | guestp->pip.mem_offset = membase - | |
321 | guestp->pip.real_base; | |
322 | } | |
323 | if (!md_node_get_val(mdp, base_mblock, MDNAME(memsize), | |
324 | &base_memsize)) { | |
325 | base_memsize = 0; | |
326 | } | |
327 | if (guestp->pip.real_limit < (realbase + base_memsize)) | |
328 | guestp->pip.real_limit = (realbase + base_memsize); | |
329 | } | |
330 | ||
331 | if (base_mblock == NULL) { | |
332 | DBG(c_printf("Missing mblock node in guest node\n")); | |
333 | goto missing_prop; | |
334 | } | |
335 | ||
336 | if (!md_node_get_val(mdp, base_mblock, MDNAME(memsize), | |
337 | &base_memsize)) { | |
338 | DBG(c_printf("Missing memsize in mblock node\n")); | |
339 | goto missing_prop; | |
340 | } | |
341 | ||
342 | if (guestp->pip.rom_size > base_memsize) { | |
343 | *fail_codep = HVctl_e_guest_base_mblock_too_small; | |
344 | return (HVctl_st_badmd); | |
345 | } | |
346 | ||
347 | #undef GET_PROPERTY | |
348 | ||
349 | ||
350 | /* | |
351 | * Look for the "perfctraccess" property. This property | |
352 | * must be present and set to a non-zero value for the | |
353 | * guest to have access to the JBUS/DRAM perf counters | |
354 | */ | |
355 | ||
356 | /* | |
357 | * FIXME; These probably need to be their own resource ! | |
358 | */ | |
359 | ||
360 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(perfctraccess), | |
361 | &guestp->pip.perfreg_accessible)) { | |
362 | guestp->pip.perfreg_accessible = 0; | |
363 | } | |
364 | ||
365 | /* | |
366 | * Look for "diagpriv" property. This property enables | |
367 | * the guest to execute arbitrary hyperprivileged code. | |
368 | */ | |
369 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(diagpriv), | |
370 | &guestp->pip.diagpriv)) { | |
371 | #ifdef CONFIG_BRINGUP | |
372 | guestp->pip.diagpriv = -1; | |
373 | #else | |
374 | guestp->pip.diagpriv = 0; | |
375 | #endif | |
376 | } | |
377 | ||
378 | /* | |
379 | * Look for "rngctlaccessible" property. This property enables | |
380 | * the guest to access the N2 RNG if available. | |
381 | */ | |
382 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(rngctlaccessible), | |
383 | &guestp->rng_ctl_accessible)) { | |
384 | guestp->rng_ctl_accessible = 0; | |
385 | } | |
386 | ||
387 | /* | |
388 | * Look for "perfctrhtaccess" property. This property enables | |
389 | * the guest to access the N2 hyper-privileged events if available. | |
390 | */ | |
391 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(perfctrhtaccess), | |
392 | &guestp->perfreght_accessible)) { | |
393 | guestp->perfreght_accessible = 0; | |
394 | } | |
395 | ||
396 | /* | |
397 | * Per guest TOD offset ... | |
398 | * FIXME: | |
399 | * This property doesn't trigger a modify op if the guest is already | |
400 | * live. So changes are only visible after a reconfig when the | |
401 | * domain is stopped. | |
402 | */ | |
403 | if (!md_node_get_val(mdp, guest_nodep, MDNAME(todoffset), | |
404 | &guestp->pip.tod_offset)) { | |
405 | guestp->pip.tod_offset = 0; | |
406 | } | |
407 | ||
408 | /* | |
409 | * Now look for the guest devices ... | |
410 | * FIXME: Needs updating so devices can be DR'd in. | |
411 | */ | |
412 | ||
413 | if (NULL != md_find_node_by_arc(mdp, guest_nodep, MDARC(MDNAME(fwd)), | |
414 | MDNODE(MDNAME(virtual_devices)), &devices_nodep)) { | |
415 | if (!md_node_get_val(mdp, devices_nodep, MDNAME(cfghandle), | |
416 | &cfg_handle)) { | |
417 | DBG(c_printf("Missing cfg_handle in device node\n")); | |
418 | goto missing_prop; | |
419 | } | |
420 | DBG(md_dump_node(mdp, devices_nodep)); | |
421 | guestp->pip.vdev_cfghandle = cfg_handle; | |
422 | } | |
423 | ||
424 | if (NULL != md_find_node_by_arc(mdp, guest_nodep, MDARC(MDNAME(fwd)), | |
425 | MDNODE(MDNAME(channel_devices)), &devices_nodep)) { | |
426 | if (!md_node_get_val(mdp, devices_nodep, MDNAME(cfghandle), | |
427 | &cfg_handle)) { | |
428 | DBG(c_printf("Missing cfg_handle in device node\n")); | |
429 | goto missing_prop; | |
430 | } | |
431 | DBG(md_dump_node(mdp, devices_nodep)); | |
432 | guestp->pip.cdev_cfghandle = cfg_handle; | |
433 | } | |
434 | DBG(c_printf("End of guest parse 1\n")); | |
435 | ||
436 | /* | |
437 | * Now we go and figureout what we need to do to the | |
438 | * guest to update or configure its state. | |
439 | * | |
440 | * Memory was dealt with earlier. | |
441 | */ | |
442 | if (guestp->state == GUEST_STATE_UNCONFIGURED) { | |
443 | DBG(c_printf("\t\tElected to config guest\n")); | |
444 | guestp->pip.res.flags = RESF_Config; | |
445 | } else { | |
446 | /* | |
447 | * what kind of a re-configure is this ? | |
448 | * Since guest structures dont really bind to anything, stuff | |
449 | * binds to them, this is a modify IMHO, but only if stuff | |
450 | * actually got modified .. | |
451 | * | |
452 | * Note: it is implicit in this test that an MD update | |
453 | * *requires* that the mdpa changes. Since the prospect of | |
454 | * and MD update inplace while the guest is running is | |
455 | * frightening and likely to break the guest this is a | |
456 | * suffient condion. If Zeus updates the MD in place we | |
457 | * have really big problems on our hands .. not sure we | |
458 | * can detect this easily. | |
459 | * | |
460 | * We ignore dynamic updates of uartbase and diskpa | |
461 | * since they should be detected above and denied if the | |
462 | * the domain is running. | |
463 | */ | |
464 | ||
465 | if (guestp->pip.rom_base != guestp->rom_base || | |
466 | guestp->pip.rom_size != guestp->rom_size || | |
467 | guestp->pip.md_pa != guestp->md_pa || | |
468 | guestp->pip.reset_reason != guestp->reset_reason || | |
469 | guestp->pip.perfreg_accessible != | |
470 | guestp->perfreg_accessible || | |
471 | guestp->pip.diagpriv != guestp->diagpriv || | |
472 | ((guestp->pip.vdev_cfghandle != INVALID_CFGHANDLE) && | |
473 | (guestp->pip.vdev_cfghandle != guestp->vdev_cfghandle)) || | |
474 | ((guestp->pip.cdev_cfghandle != INVALID_CFGHANDLE) && | |
475 | (guestp->pip.cdev_cfghandle != guestp->cdev_cfghandle)) || | |
476 | guestp->pip.tod_offset != guestp->tod_offset) { | |
477 | DBG(c_printf("\t\tElected to modify guest\n")); | |
478 | guestp->pip.res.flags = RESF_Modify; | |
479 | } else { | |
480 | guestp->pip.res.flags = RESF_Noop; | |
481 | DBG(c_printf("\t\tElected to ignore guest\n")); | |
482 | } | |
483 | } | |
484 | ||
485 | return (HVctl_st_ok); | |
486 | ||
487 | missing_prop:; | |
488 | *fail_codep = HVctl_e_guest_missing_property; | |
489 | return (HVctl_st_badmd); | |
490 | } | |
491 | ||
492 | ||
493 | /* | |
494 | * Simple suite of checks based on the flags for this resource | |
495 | */ | |
496 | ||
497 | hvctl_status_t | |
498 | res_guest_postparse(hvctl_res_error_t *fail_codep, int *fail_res_idp) | |
499 | { | |
500 | guest_t *gp; | |
501 | int i; | |
502 | ||
503 | gp = config.guests; | |
504 | ||
505 | for (i = 0; i < NGUESTS; i++, gp++) { | |
506 | switch (gp->pip.res.flags) { | |
507 | case RESF_Noop: | |
508 | break; | |
509 | case RESF_Unconfig: | |
510 | if (gp->state != GUEST_STATE_STOPPED) { | |
511 | *fail_codep = HVctl_e_guest_active; | |
512 | goto fail; | |
513 | } | |
514 | break; | |
515 | case RESF_Config: | |
516 | break; | |
517 | case RESF_Rebind: | |
518 | ASSERT(0); /* not supported */ | |
519 | break; | |
520 | case RESF_Modify: | |
521 | break; | |
522 | default: | |
523 | ASSERT(0); | |
524 | } | |
525 | } | |
526 | return (HVctl_st_ok); | |
527 | ||
528 | fail: | |
529 | *fail_res_idp = i; | |
530 | return (HVctl_st_badmd); | |
531 | } | |
532 | ||
533 | ||
534 | ||
535 | ||
536 | void | |
537 | res_guest_commit(int flag) | |
538 | { | |
539 | guest_t *gp; | |
540 | int i; | |
541 | ||
542 | gp = config.guests; | |
543 | ||
544 | for (i = 0; i < NGUESTS; i++, gp++) { | |
545 | /* if not this ops turn move on */ | |
546 | if (gp->pip.res.flags != flag) continue; | |
547 | ||
548 | switch (gp->pip.res.flags) { | |
549 | case RESF_Noop: | |
550 | DBG(c_printf("guest 0x%x : noop\n", i)); | |
551 | break; | |
552 | case RESF_Unconfig: | |
553 | res_guest_commit_unconfig(gp); | |
554 | break; | |
555 | case RESF_Config: | |
556 | res_guest_commit_config(gp); | |
557 | break; | |
558 | case RESF_Rebind: | |
559 | DBG(c_printf("guest 0x%x : rebind\n", i)); | |
560 | ASSERT(0); /* not supported */ | |
561 | break; | |
562 | case RESF_Modify: | |
563 | res_guest_commit_modify(gp); | |
564 | break; | |
565 | default: | |
566 | ASSERT(0); | |
567 | } | |
568 | ||
569 | gp->pip.res.flags = RESF_Noop; /* cleanup */ | |
570 | } | |
571 | } | |
572 | ||
573 | ||
574 | void | |
575 | reset_guest_state(guest_t *guestp) | |
576 | { | |
577 | ASSERT(guestp->state == GUEST_STATE_STOPPED); | |
578 | ||
579 | reset_api_hcall_table(guestp); | |
580 | DBG(c_printf("\tguest hcall table @ 0x%x\n", guestp->hcall_table)); | |
581 | ||
582 | reset_guest_perm_mappings(guestp); | |
583 | ||
584 | reset_guest_ldc_mapins(guestp); | |
585 | } | |
586 | ||
587 | ||
588 | /* | |
589 | * reconfigure common path - also shared with commit | |
590 | */ | |
591 | void | |
592 | res_guest_commit_modify(guest_t *guestp) | |
593 | { | |
594 | DBG(c_printf("modify guest 0x%x\n", guestp->guestid)); | |
595 | ASSERT(guestp->state != GUEST_STATE_UNCONFIGURED); | |
596 | ||
597 | guestp->rom_base = guestp->pip.rom_base; | |
598 | guestp->rom_size = guestp->pip.rom_size; | |
599 | guestp->real_base = guestp->pip.real_base; | |
600 | guestp->real_limit = guestp->pip.real_limit; | |
601 | guestp->mem_offset = guestp->pip.mem_offset; | |
602 | ||
603 | guestp->md_pa = guestp->pip.md_pa; | |
604 | /* | |
605 | * Compute the Guests MD size | |
606 | */ | |
607 | config_guest_md(guestp); | |
608 | ||
609 | ||
610 | #ifdef CONFIG_DISK | |
611 | guestp->disk.size = 0LL; | |
612 | guestp->disk.pa = guestp->pip.diskpa; | |
613 | #endif | |
614 | ||
615 | #ifdef T1_FPGA_SNET | |
616 | guestp->snet.ino = guestp->pip.snet_ino; | |
617 | guestp->snet.pa = guestp->pip.snet_pa; | |
618 | #endif | |
619 | ||
620 | /* | |
621 | * Look for the "perfctraccess" property. This property | |
622 | * must be present and set to a non-zero value for the | |
623 | * guest to have access to the JBUS/DRAM perf counters | |
624 | */ | |
625 | guestp->perfreg_accessible = guestp->pip.perfreg_accessible; | |
626 | ||
627 | /* | |
628 | * Look for "diagpriv" property. This property enables | |
629 | * the guest to execute arbitrary hyperprivileged code. | |
630 | */ | |
631 | guestp->diagpriv = guestp->pip.diagpriv; | |
632 | ||
633 | /* | |
634 | * Assume entry point is at base of real memory | |
635 | */ | |
636 | guestp->entry = guestp->real_base; | |
637 | guestp->reset_reason = guestp->pip.reset_reason; | |
638 | ||
639 | /* | |
640 | * Modify devops. | |
641 | */ | |
642 | unconfig_guest_virtual_device(guestp); | |
643 | unconfig_guest_channel_device(guestp); | |
644 | config_guest_virtual_device(guestp, guestp->pip.vdev_cfghandle); | |
645 | config_guest_channel_device(guestp, guestp->pip.cdev_cfghandle); | |
646 | ||
647 | } | |
648 | ||
649 | ||
650 | void | |
651 | res_guest_commit_config(guest_t *guestp) | |
652 | { | |
653 | int x; | |
654 | ||
655 | DBG(c_printf("commit config guest 0x%x : config\n", guestp->guestid)); | |
656 | ASSERT(guestp->state == GUEST_STATE_UNCONFIGURED); | |
657 | ||
658 | /* | |
659 | * Now fill in basic properties for this guest ... | |
660 | * | |
661 | * FIXME: These should be available if the guest is | |
662 | * live yes ? | |
663 | */ | |
664 | guestp->ldc_mapin_basera = LDC_MAPIN_BASERA; | |
665 | guestp->ldc_mapin_size = LDC_MAPIN_RASIZE; | |
666 | ||
667 | guestp->state = GUEST_STATE_STOPPED; | |
668 | res_guest_commit_modify(guestp); | |
669 | ||
670 | /* | |
671 | * TOD is configured once at the begining of time. | |
672 | * we don't allow external modifies as that would warp | |
673 | * the time value each time the guest gets and update | |
674 | * after the guest had modified itself. | |
675 | */ | |
676 | guestp->tod_offset = guestp->pip.tod_offset; | |
677 | ||
678 | /* | |
679 | * At the time of first guest config mark all INO2LDC | |
680 | * mappings as NULL | |
681 | */ | |
682 | for (x = 0; x < MAX_LDC_INOS; x++) { | |
683 | guestp->ldc_ino2endpoint[x].endpointp = NULL; | |
684 | guestp->ldc_ino2endpoint[x].mapregp = NULL; | |
685 | } | |
686 | ||
687 | /* | |
688 | * FIXME: Should we really care to track this - why not | |
689 | * just use the constant; MAX_LDC_CHANNELS | |
690 | */ | |
691 | guestp->ldc_max_channel_idx = MAX_LDC_CHANNELS; | |
692 | /* we might check that all the LDC endpoints are !live */ | |
693 | /* kind of pointless since we are moving them to a global */ | |
694 | ||
695 | ||
696 | /* | |
697 | * clear out the devops table. | |
698 | */ | |
699 | for (int y = 0; y < NVINOS; y++) { | |
700 | guestp->vino2inst.vino[y] = DEVOPS_RESERVED; | |
701 | } | |
702 | ||
703 | for (int x = 0; x < NDEVIDS; x++) { | |
704 | guestp->dev2inst[x] = DEVOPS_RESERVED; | |
705 | } | |
706 | ||
707 | config_guest_virtual_device(guestp, guestp->pip.vdev_cfghandle); | |
708 | config_guest_channel_device(guestp, guestp->pip.cdev_cfghandle); | |
709 | ||
710 | ||
711 | /* until we boot it ... */ | |
712 | ASSERT(guestp->state == GUEST_STATE_STOPPED); | |
713 | reset_guest_state(guestp); | |
714 | ||
715 | ||
716 | DBG(c_printf("End of guest setup\n")); | |
717 | } | |
718 | ||
719 | ||
720 | void | |
721 | res_guest_commit_unconfig(guest_t *guestp) | |
722 | { | |
723 | /* preserve the guest ID ... err thats about it */ | |
724 | ||
725 | DBG(c_printf("guest 0x%x : unconfig\n", guestp->guestid)); | |
726 | ||
727 | ASSERT(guestp->state == GUEST_STATE_STOPPED); | |
728 | ||
729 | unconfig_guest_virtual_device(guestp); | |
730 | unconfig_guest_channel_device(guestp); | |
731 | /* | |
732 | * clear out the devops table. | |
733 | */ | |
734 | for (int y = 0; y < NVINOS; y++) { | |
735 | guestp->vino2inst.vino[y] = DEVOPS_RESERVED; | |
736 | } | |
737 | ||
738 | for (int x = 0; x < NDEVIDS; x++) { | |
739 | guestp->dev2inst[x] = DEVOPS_RESERVED; | |
740 | } | |
741 | ||
742 | ||
743 | init_guest(guestp->guestid); | |
744 | ||
745 | /* Just incase we add more phases */ | |
746 | guestp->pip.res.flags = RESF_Noop; | |
747 | } | |
748 | ||
749 | void | |
750 | config_a_guest_device_vino(guest_t *guestp, int ino, uint8_t type) | |
751 | { | |
752 | uint64_t cfg_handle = INVALID_CFGHANDLE; | |
753 | ||
754 | switch (type) { | |
755 | case DEVOPS_VDEV: | |
756 | cfg_handle = guestp->vdev_cfghandle; | |
757 | break; | |
758 | case DEVOPS_CDEV: | |
759 | cfg_handle = guestp->cdev_cfghandle; | |
760 | break; | |
761 | default: | |
762 | break; | |
763 | }; | |
764 | ||
765 | DBG(c_printf("guest device:\n\tcfg handle 0x%x 0x%x\n", | |
766 | cfg_handle, ino)); | |
767 | ASSERT(cfg_handle != INVALID_CFGHANDLE); | |
768 | guestp->vino2inst.vino[cfg_handle + ino] = type; | |
769 | ||
770 | } | |
771 | ||
772 | void | |
773 | unconfig_a_guest_device_vino(guest_t *guestp, int ino, uint8_t type) | |
774 | { | |
775 | uint64_t cfg_handle = INVALID_CFGHANDLE; | |
776 | ||
777 | switch (type) { | |
778 | case DEVOPS_VDEV: | |
779 | cfg_handle = guestp->vdev_cfghandle; | |
780 | break; | |
781 | case DEVOPS_CDEV: | |
782 | cfg_handle = guestp->cdev_cfghandle; | |
783 | break; | |
784 | default: | |
785 | break; | |
786 | }; | |
787 | ||
788 | ASSERT(cfg_handle != INVALID_CFGHANDLE); | |
789 | guestp->vino2inst.vino[cfg_handle + ino] = DEVOPS_RESERVED; | |
790 | ||
791 | } | |
792 | ||
793 | void | |
794 | config_guest_virtual_device(guest_t *guestp, uint64_t cfg_handle) | |
795 | { | |
796 | uint8_t devid; | |
797 | ||
798 | ASSERT(cfg_handle != INVALID_CFGHANDLE); | |
799 | if (cfg_handle == INVALID_CFGHANDLE) | |
800 | return; | |
801 | ||
802 | guestp->vdev_cfghandle = cfg_handle; | |
803 | ||
804 | devid = guestp->vdev_cfghandle >> DEVCFGPA_SHIFT; | |
805 | guestp->dev2inst[devid] = DEVOPS_VDEV; | |
806 | } | |
807 | ||
808 | void | |
809 | unconfig_guest_virtual_device(guest_t *guestp) | |
810 | { | |
811 | uint8_t devid; | |
812 | ||
813 | devid = guestp->vdev_cfghandle >> DEVCFGPA_SHIFT; | |
814 | guestp->dev2inst[devid] = DEVOPS_RESERVED; | |
815 | ||
816 | guestp->vdev_cfghandle = INVALID_CFGHANDLE; | |
817 | ||
818 | } | |
819 | ||
820 | void | |
821 | config_guest_channel_device(guest_t *guestp, uint64_t cfg_handle) | |
822 | { | |
823 | uint8_t devid, edevid; | |
824 | int x; | |
825 | ||
826 | ASSERT(cfg_handle != INVALID_CFGHANDLE); | |
827 | if (cfg_handle == INVALID_CFGHANDLE) | |
828 | return; | |
829 | ||
830 | guestp->cdev_cfghandle = cfg_handle; | |
831 | ||
832 | devid = guestp->cdev_cfghandle >> DEVCFGPA_SHIFT; | |
833 | edevid = (guestp->cdev_cfghandle + MAX_LDC_INOS) >> DEVCFGPA_SHIFT; | |
834 | ||
835 | for (x = devid; x < edevid; x++) | |
836 | guestp->dev2inst[x] = DEVOPS_CDEV; | |
837 | ||
838 | } | |
839 | ||
840 | void | |
841 | unconfig_guest_channel_device(guest_t *guestp) | |
842 | { | |
843 | uint8_t devid, edevid; | |
844 | int x; | |
845 | ||
846 | devid = guestp->cdev_cfghandle >> DEVCFGPA_SHIFT; | |
847 | edevid = (guestp->cdev_cfghandle + MAX_LDC_INOS) >> DEVCFGPA_SHIFT; | |
848 | ||
849 | for (x = devid; x < edevid; x++) | |
850 | guestp->dev2inst[x] = DEVOPS_RESERVED; | |
851 | ||
852 | guestp->cdev_cfghandle = INVALID_CFGHANDLE; | |
853 | ||
854 | } |