blob: e4b82319881db227044550b3330f1eea69770f50 [file] [log] [blame]
Xiantao Zhangad86b6c2008-04-01 14:59:30 +08001/*
2 * PAL/SAL call delegation
3 *
4 * Copyright (c) 2004 Li Susie <susie.li@intel.com>
5 * Copyright (c) 2005 Yu Ke <ke.yu@intel.com>
6 * Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 */
21
22#include <linux/kvm_host.h>
23#include <linux/smp.h>
Jes Sorensence17c642009-02-25 10:38:54 -060024#include <asm/sn/addrs.h>
25#include <asm/sn/clksupport.h>
26#include <asm/sn/shub_mmr.h>
Xiantao Zhangad86b6c2008-04-01 14:59:30 +080027
28#include "vti.h"
29#include "misc.h"
30
31#include <asm/pal.h>
32#include <asm/sal.h>
33#include <asm/tlb.h>
34
35/*
36 * Handy macros to make sure that the PAL return values start out
37 * as something meaningful.
38 */
39#define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
40 { \
41 x.status = PAL_STATUS_UNIMPLEMENTED; \
42 x.v0 = 0; \
43 x.v1 = 0; \
44 x.v2 = 0; \
45 }
46
47#define INIT_PAL_STATUS_SUCCESS(x) \
48 { \
49 x.status = PAL_STATUS_SUCCESS; \
50 x.v0 = 0; \
51 x.v1 = 0; \
52 x.v2 = 0; \
53 }
54
55static void kvm_get_pal_call_data(struct kvm_vcpu *vcpu,
56 u64 *gr28, u64 *gr29, u64 *gr30, u64 *gr31) {
57 struct exit_ctl_data *p;
58
59 if (vcpu) {
60 p = &vcpu->arch.exit_data;
61 if (p->exit_reason == EXIT_REASON_PAL_CALL) {
62 *gr28 = p->u.pal_data.gr28;
63 *gr29 = p->u.pal_data.gr29;
64 *gr30 = p->u.pal_data.gr30;
65 *gr31 = p->u.pal_data.gr31;
66 return ;
67 }
68 }
69 printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
70}
71
72static void set_pal_result(struct kvm_vcpu *vcpu,
73 struct ia64_pal_retval result) {
74
75 struct exit_ctl_data *p;
76
77 p = kvm_get_exit_data(vcpu);
78 if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
79 p->u.pal_data.ret = result;
80 return ;
81 }
82 INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
83}
84
85static void set_sal_result(struct kvm_vcpu *vcpu,
86 struct sal_ret_values result) {
87 struct exit_ctl_data *p;
88
89 p = kvm_get_exit_data(vcpu);
90 if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
91 p->u.sal_data.ret = result;
92 return ;
93 }
94 printk(KERN_WARNING"Failed to set sal result!!\n");
95}
96
97struct cache_flush_args {
98 u64 cache_type;
99 u64 operation;
100 u64 progress;
101 long status;
102};
103
104cpumask_t cpu_cache_coherent_map;
105
106static void remote_pal_cache_flush(void *data)
107{
108 struct cache_flush_args *args = data;
109 long status;
110 u64 progress = args->progress;
111
112 status = ia64_pal_cache_flush(args->cache_type, args->operation,
113 &progress, NULL);
114 if (status != 0)
115 args->status = status;
116}
117
118static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
119{
120 u64 gr28, gr29, gr30, gr31;
121 struct ia64_pal_retval result = {0, 0, 0, 0};
122 struct cache_flush_args args = {0, 0, 0, 0};
123 long psr;
124
125 gr28 = gr29 = gr30 = gr31 = 0;
126 kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
127
128 if (gr31 != 0)
129 printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
130
131 /* Always call Host Pal in int=1 */
132 gr30 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
133 args.cache_type = gr29;
134 args.operation = gr30;
135 smp_call_function(remote_pal_cache_flush,
Takashi Iwai2f73cca2008-07-17 18:09:12 +0200136 (void *)&args, 1);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800137 if (args.status != 0)
138 printk(KERN_ERR"pal_cache_flush error!,"
139 "status:0x%lx\n", args.status);
140 /*
141 * Call Host PAL cache flush
142 * Clear psr.ic when call PAL_CACHE_FLUSH
143 */
144 local_irq_save(psr);
145 result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
146 &result.v0);
147 local_irq_restore(psr);
148 if (result.status != 0)
149 printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
150 "in1:%lx,in2:%lx\n",
151 vcpu, result.status, gr29, gr30);
152
153#if 0
154 if (gr29 == PAL_CACHE_TYPE_COHERENT) {
155 cpus_setall(vcpu->arch.cache_coherent_map);
156 cpu_clear(vcpu->cpu, vcpu->arch.cache_coherent_map);
157 cpus_setall(cpu_cache_coherent_map);
158 cpu_clear(vcpu->cpu, cpu_cache_coherent_map);
159 }
160#endif
161 return result;
162}
163
164struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
165{
166
167 struct ia64_pal_retval result;
168
169 PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
170 return result;
171}
172
173static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
174{
175
176 struct ia64_pal_retval result;
177
178 PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
179
180 /*
181 * PAL_FREQ_BASE may not be implemented in some platforms,
182 * call SAL instead.
183 */
184 if (result.v0 == 0) {
185 result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
186 &result.v0,
187 &result.v1);
188 result.v2 = 0;
189 }
190
191 return result;
192}
193
Jes Sorensence17c642009-02-25 10:38:54 -0600194/*
195 * On the SGI SN2, the ITC isn't stable. Emulation backed by the SN2
196 * RTC is used instead. This function patches the ratios from SAL
197 * to match the RTC before providing them to the guest.
198 */
199static void sn2_patch_itc_freq_ratios(struct ia64_pal_retval *result)
200{
201 struct pal_freq_ratio *ratio;
202 unsigned long sal_freq, sal_drift, factor;
203
204 result->status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
205 &sal_freq, &sal_drift);
206 ratio = (struct pal_freq_ratio *)&result->v2;
207 factor = ((sal_freq * 3) + (sn_rtc_cycles_per_second / 2)) /
208 sn_rtc_cycles_per_second;
209
210 ratio->num = 3;
211 ratio->den = factor;
212}
213
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800214static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
215{
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800216 struct ia64_pal_retval result;
217
218 PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
Jes Sorensence17c642009-02-25 10:38:54 -0600219
220 if (vcpu->kvm->arch.is_sn2)
221 sn2_patch_itc_freq_ratios(&result);
222
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800223 return result;
224}
225
226static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
227{
228 struct ia64_pal_retval result;
229
230 INIT_PAL_STATUS_UNIMPLEMENTED(result);
231 return result;
232}
233
234static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
235{
236
237 struct ia64_pal_retval result;
238
239 INIT_PAL_STATUS_SUCCESS(result);
240 return result;
241}
242
243static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
244{
245
246 struct ia64_pal_retval result = {0, 0, 0, 0};
247 long in0, in1, in2, in3;
248
249 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
250 result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
251 &result.v2, in2);
252
253 return result;
254}
255
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800256static struct ia64_pal_retval pal_register_info(struct kvm_vcpu *vcpu)
257{
258
259 struct ia64_pal_retval result = {0, 0, 0, 0};
260 long in0, in1, in2, in3;
261
262 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
263 result.status = ia64_pal_register_info(in1, &result.v1, &result.v2);
264
265 return result;
266}
267
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800268static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
269{
270
271 pal_cache_config_info_t ci;
272 long status;
273 unsigned long in0, in1, in2, in3, r9, r10;
274
275 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
276 status = ia64_pal_cache_config_info(in1, in2, &ci);
277 r9 = ci.pcci_info_1.pcci1_data;
278 r10 = ci.pcci_info_2.pcci2_data;
279 return ((struct ia64_pal_retval){status, r9, r10, 0});
280}
281
282#define GUEST_IMPL_VA_MSB 59
283#define GUEST_RID_BITS 18
284
285static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
286{
287
288 pal_vm_info_1_u_t vminfo1;
289 pal_vm_info_2_u_t vminfo2;
290 struct ia64_pal_retval result;
291
292 PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
293 if (!result.status) {
294 vminfo1.pvi1_val = result.v0;
295 vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
296 vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
297 result.v0 = vminfo1.pvi1_val;
298 vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
299 vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
300 result.v1 = vminfo2.pvi2_val;
301 }
302
303 return result;
304}
305
306static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
307{
308 struct ia64_pal_retval result;
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800309 unsigned long in0, in1, in2, in3;
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800310
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800311 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
312
313 result.status = ia64_pal_vm_info(in1, in2,
314 (pal_tc_info_u_t *)&result.v1, &result.v2);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800315
316 return result;
317}
318
319static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
320{
321 u64 index = 0;
322 struct exit_ctl_data *p;
323
324 p = kvm_get_exit_data(vcpu);
325 if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
326 index = p->u.pal_data.gr28;
327
328 return index;
329}
330
Xiantao Zhangdecc9012008-10-16 15:58:15 +0800331static void prepare_for_halt(struct kvm_vcpu *vcpu)
332{
333 vcpu->arch.timer_pending = 1;
334 vcpu->arch.timer_fired = 0;
335}
336
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800337static struct ia64_pal_retval pal_perf_mon_info(struct kvm_vcpu *vcpu)
338{
339 long status;
340 unsigned long in0, in1, in2, in3, r9;
341 unsigned long pm_buffer[16];
342
343 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
344 status = ia64_pal_perf_mon_info(pm_buffer,
345 (pal_perf_mon_info_u_t *) &r9);
346 if (status != 0) {
347 printk(KERN_DEBUG"PAL_PERF_MON_INFO fails ret=%ld\n", status);
348 } else {
349 if (in1)
350 memcpy((void *)in1, pm_buffer, sizeof(pm_buffer));
351 else {
352 status = PAL_STATUS_EINVAL;
353 printk(KERN_WARNING"Invalid parameters "
354 "for PAL call:0x%lx!\n", in0);
355 }
356 }
357 return (struct ia64_pal_retval){status, r9, 0, 0};
358}
359
360static struct ia64_pal_retval pal_halt_info(struct kvm_vcpu *vcpu)
361{
362 unsigned long in0, in1, in2, in3;
363 long status;
364 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
365 | (1UL << 61) | (1UL << 60);
366
367 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
368 if (in1) {
369 memcpy((void *)in1, &res, sizeof(res));
370 status = 0;
371 } else{
372 status = PAL_STATUS_EINVAL;
373 printk(KERN_WARNING"Invalid parameters "
374 "for PAL call:0x%lx!\n", in0);
375 }
376
377 return (struct ia64_pal_retval){status, 0, 0, 0};
378}
379
380static struct ia64_pal_retval pal_mem_attrib(struct kvm_vcpu *vcpu)
381{
382 unsigned long r9;
383 long status;
384
385 status = ia64_pal_mem_attrib(&r9);
386
387 return (struct ia64_pal_retval){status, r9, 0, 0};
388}
389
390static void remote_pal_prefetch_visibility(void *v)
391{
392 s64 trans_type = (s64)v;
393 ia64_pal_prefetch_visibility(trans_type);
394}
395
396static struct ia64_pal_retval pal_prefetch_visibility(struct kvm_vcpu *vcpu)
397{
398 struct ia64_pal_retval result = {0, 0, 0, 0};
399 unsigned long in0, in1, in2, in3;
400 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
401 result.status = ia64_pal_prefetch_visibility(in1);
402 if (result.status == 0) {
403 /* Must be performed on all remote processors
404 in the coherence domain. */
405 smp_call_function(remote_pal_prefetch_visibility,
406 (void *)in1, 1);
407 /* Unnecessary on remote processor for other vcpus!*/
408 result.status = 1;
409 }
410 return result;
411}
412
413static void remote_pal_mc_drain(void *v)
414{
415 ia64_pal_mc_drain();
416}
417
418static struct ia64_pal_retval pal_get_brand_info(struct kvm_vcpu *vcpu)
419{
420 struct ia64_pal_retval result = {0, 0, 0, 0};
421 unsigned long in0, in1, in2, in3;
422
423 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
424
425 if (in1 == 0 && in2) {
426 char brand_info[128];
427 result.status = ia64_pal_get_brand_info(brand_info);
428 if (result.status == PAL_STATUS_SUCCESS)
429 memcpy((void *)in2, brand_info, 128);
430 } else {
431 result.status = PAL_STATUS_REQUIRES_MEMORY;
432 printk(KERN_WARNING"Invalid parameters for "
433 "PAL call:0x%lx!\n", in0);
434 }
435
436 return result;
437}
438
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800439int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
440{
441
442 u64 gr28;
443 struct ia64_pal_retval result;
444 int ret = 1;
445
446 gr28 = kvm_get_pal_call_index(vcpu);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800447 switch (gr28) {
448 case PAL_CACHE_FLUSH:
449 result = pal_cache_flush(vcpu);
450 break;
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800451 case PAL_MEM_ATTRIB:
452 result = pal_mem_attrib(vcpu);
453 break;
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800454 case PAL_CACHE_SUMMARY:
455 result = pal_cache_summary(vcpu);
456 break;
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800457 case PAL_PERF_MON_INFO:
458 result = pal_perf_mon_info(vcpu);
459 break;
460 case PAL_HALT_INFO:
461 result = pal_halt_info(vcpu);
462 break;
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800463 case PAL_HALT_LIGHT:
464 {
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800465 INIT_PAL_STATUS_SUCCESS(result);
Xiantao Zhangdecc9012008-10-16 15:58:15 +0800466 prepare_for_halt(vcpu);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800467 if (kvm_highest_pending_irq(vcpu) == -1)
468 ret = kvm_emulate_halt(vcpu);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800469 }
470 break;
471
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800472 case PAL_PREFETCH_VISIBILITY:
473 result = pal_prefetch_visibility(vcpu);
474 break;
475 case PAL_MC_DRAIN:
476 result.status = ia64_pal_mc_drain();
477 /* FIXME: All vcpus likely call PAL_MC_DRAIN.
478 That causes the congestion. */
479 smp_call_function(remote_pal_mc_drain, NULL, 1);
480 break;
481
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800482 case PAL_FREQ_RATIOS:
483 result = pal_freq_ratios(vcpu);
484 break;
485
486 case PAL_FREQ_BASE:
487 result = pal_freq_base(vcpu);
488 break;
489
490 case PAL_LOGICAL_TO_PHYSICAL :
491 result = pal_logical_to_physica(vcpu);
492 break;
493
494 case PAL_VM_SUMMARY :
495 result = pal_vm_summary(vcpu);
496 break;
497
498 case PAL_VM_INFO :
499 result = pal_vm_info(vcpu);
500 break;
501 case PAL_PLATFORM_ADDR :
502 result = pal_platform_addr(vcpu);
503 break;
504 case PAL_CACHE_INFO:
505 result = pal_cache_info(vcpu);
506 break;
507 case PAL_PTCE_INFO:
508 INIT_PAL_STATUS_SUCCESS(result);
509 result.v1 = (1L << 32) | 1L;
510 break;
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800511 case PAL_REGISTER_INFO:
512 result = pal_register_info(vcpu);
513 break;
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800514 case PAL_VM_PAGE_SIZE:
515 result.status = ia64_pal_vm_page_size(&result.v0,
516 &result.v1);
517 break;
518 case PAL_RSE_INFO:
519 result.status = ia64_pal_rse_info(&result.v0,
520 (pal_hints_u_t *)&result.v1);
521 break;
522 case PAL_PROC_GET_FEATURES:
523 result = pal_proc_get_features(vcpu);
524 break;
525 case PAL_DEBUG_INFO:
526 result.status = ia64_pal_debug_info(&result.v0,
527 &result.v1);
528 break;
529 case PAL_VERSION:
530 result.status = ia64_pal_version(
531 (pal_version_u_t *)&result.v0,
532 (pal_version_u_t *)&result.v1);
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800533 break;
534 case PAL_FIXED_ADDR:
535 result.status = PAL_STATUS_SUCCESS;
536 result.v0 = vcpu->vcpu_id;
537 break;
Xiantao Zhang7d656bd2009-01-21 11:21:27 +0800538 case PAL_BRAND_INFO:
539 result = pal_get_brand_info(vcpu);
540 break;
541 case PAL_GET_PSTATE:
542 case PAL_CACHE_SHARED_INFO:
543 INIT_PAL_STATUS_UNIMPLEMENTED(result);
544 break;
Xiantao Zhangad86b6c2008-04-01 14:59:30 +0800545 default:
546 INIT_PAL_STATUS_UNIMPLEMENTED(result);
547 printk(KERN_WARNING"kvm: Unsupported pal call,"
548 " index:0x%lx\n", gr28);
549 }
550 set_pal_result(vcpu, result);
551 return ret;
552}
553
554static struct sal_ret_values sal_emulator(struct kvm *kvm,
555 long index, unsigned long in1,
556 unsigned long in2, unsigned long in3,
557 unsigned long in4, unsigned long in5,
558 unsigned long in6, unsigned long in7)
559{
560 unsigned long r9 = 0;
561 unsigned long r10 = 0;
562 long r11 = 0;
563 long status;
564
565 status = 0;
566 switch (index) {
567 case SAL_FREQ_BASE:
568 status = ia64_sal_freq_base(in1, &r9, &r10);
569 break;
570 case SAL_PCI_CONFIG_READ:
571 printk(KERN_WARNING"kvm: Not allowed to call here!"
572 " SAL_PCI_CONFIG_READ\n");
573 break;
574 case SAL_PCI_CONFIG_WRITE:
575 printk(KERN_WARNING"kvm: Not allowed to call here!"
576 " SAL_PCI_CONFIG_WRITE\n");
577 break;
578 case SAL_SET_VECTORS:
579 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
580 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
581 status = -2;
582 } else {
583 kvm->arch.rdv_sal_data.boot_ip = in2;
584 kvm->arch.rdv_sal_data.boot_gp = in3;
585 }
586 printk("Rendvous called! iip:%lx\n\n", in2);
587 } else
588 printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
589 "ignored...\n", in1);
590 break;
591 case SAL_GET_STATE_INFO:
592 /* No more info. */
593 status = -5;
594 r9 = 0;
595 break;
596 case SAL_GET_STATE_INFO_SIZE:
597 /* Return a dummy size. */
598 status = 0;
599 r9 = 128;
600 break;
601 case SAL_CLEAR_STATE_INFO:
602 /* Noop. */
603 break;
604 case SAL_MC_RENDEZ:
605 printk(KERN_WARNING
606 "kvm: called SAL_MC_RENDEZ. ignored...\n");
607 break;
608 case SAL_MC_SET_PARAMS:
609 printk(KERN_WARNING
610 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
611 break;
612 case SAL_CACHE_FLUSH:
613 if (1) {
614 /*Flush using SAL.
615 This method is faster but has a side
616 effect on other vcpu running on
617 this cpu. */
618 status = ia64_sal_cache_flush(in1);
619 } else {
620 /*Maybe need to implement the method
621 without side effect!*/
622 status = 0;
623 }
624 break;
625 case SAL_CACHE_INIT:
626 printk(KERN_WARNING
627 "kvm: called SAL_CACHE_INIT. ignored...\n");
628 break;
629 case SAL_UPDATE_PAL:
630 printk(KERN_WARNING
631 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
632 break;
633 default:
634 printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
635 " index:%ld\n", index);
636 status = -1;
637 break;
638 }
639 return ((struct sal_ret_values) {status, r9, r10, r11});
640}
641
642static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
643 u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
644
645 struct exit_ctl_data *p;
646
647 p = kvm_get_exit_data(vcpu);
648
649 if (p) {
650 if (p->exit_reason == EXIT_REASON_SAL_CALL) {
651 *in0 = p->u.sal_data.in0;
652 *in1 = p->u.sal_data.in1;
653 *in2 = p->u.sal_data.in2;
654 *in3 = p->u.sal_data.in3;
655 *in4 = p->u.sal_data.in4;
656 *in5 = p->u.sal_data.in5;
657 *in6 = p->u.sal_data.in6;
658 *in7 = p->u.sal_data.in7;
659 return ;
660 }
661 }
662 *in0 = 0;
663}
664
665void kvm_sal_emul(struct kvm_vcpu *vcpu)
666{
667
668 struct sal_ret_values result;
669 u64 index, in1, in2, in3, in4, in5, in6, in7;
670
671 kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
672 &in3, &in4, &in5, &in6, &in7);
673 result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
674 in4, in5, in6, in7);
675 set_sal_result(vcpu, result);
676}