2 * PAL/SAL call delegation
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>
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.
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
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.
22 #include <linux/kvm_host.h>
23 #include <linux/smp.h>
24 #include <asm/sn/addrs.h>
25 #include <asm/sn/clksupport.h>
26 #include <asm/sn/shub_mmr.h>
36 * Handy macros to make sure that the PAL return values start out
37 * as something meaningful.
39 #define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
41 x.status = PAL_STATUS_UNIMPLEMENTED; \
47 #define INIT_PAL_STATUS_SUCCESS(x) \
49 x.status = PAL_STATUS_SUCCESS; \
55 static 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;
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;
69 printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
72 static void set_pal_result(struct kvm_vcpu *vcpu,
73 struct ia64_pal_retval result) {
75 struct exit_ctl_data *p;
77 p = kvm_get_exit_data(vcpu);
78 if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
79 p->u.pal_data.ret = result;
82 INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
85 static void set_sal_result(struct kvm_vcpu *vcpu,
86 struct sal_ret_values result) {
87 struct exit_ctl_data *p;
89 p = kvm_get_exit_data(vcpu);
90 if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
91 p->u.sal_data.ret = result;
94 printk(KERN_WARNING"Failed to set sal result!!\n");
97 struct cache_flush_args {
104 cpumask_t cpu_cache_coherent_map;
106 static void remote_pal_cache_flush(void *data)
108 struct cache_flush_args *args = data;
110 u64 progress = args->progress;
112 status = ia64_pal_cache_flush(args->cache_type, args->operation,
115 args->status = status;
118 static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
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};
125 gr28 = gr29 = gr30 = gr31 = 0;
126 kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
129 printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
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,
137 if (args.status != 0)
138 printk(KERN_ERR"pal_cache_flush error!,"
139 "status:0x%lx\n", args.status);
141 * Call Host PAL cache flush
142 * Clear psr.ic when call PAL_CACHE_FLUSH
145 result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
147 local_irq_restore(psr);
148 if (result.status != 0)
149 printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
151 vcpu, result.status, gr29, gr30);
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);
164 struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
167 struct ia64_pal_retval result;
169 PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
173 static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
176 struct ia64_pal_retval result;
178 PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
181 * PAL_FREQ_BASE may not be implemented in some platforms,
184 if (result.v0 == 0) {
185 result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
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.
199 static void sn2_patch_itc_freq_ratios(struct ia64_pal_retval *result)
201 struct pal_freq_ratio *ratio;
202 unsigned long sal_freq, sal_drift, factor;
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;
214 static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
216 struct ia64_pal_retval result;
218 PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
220 if (vcpu->kvm->arch.is_sn2)
221 sn2_patch_itc_freq_ratios(&result);
226 static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
228 struct ia64_pal_retval result;
230 INIT_PAL_STATUS_UNIMPLEMENTED(result);
234 static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
237 struct ia64_pal_retval result;
239 INIT_PAL_STATUS_SUCCESS(result);
243 static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
246 struct ia64_pal_retval result = {0, 0, 0, 0};
247 long in0, in1, in2, in3;
249 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
250 result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
256 static struct ia64_pal_retval pal_register_info(struct kvm_vcpu *vcpu)
259 struct ia64_pal_retval result = {0, 0, 0, 0};
260 long in0, in1, in2, in3;
262 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
263 result.status = ia64_pal_register_info(in1, &result.v1, &result.v2);
268 static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
271 pal_cache_config_info_t ci;
273 unsigned long in0, in1, in2, in3, r9, r10;
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});
282 #define GUEST_IMPL_VA_MSB 59
283 #define GUEST_RID_BITS 18
285 static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
288 pal_vm_info_1_u_t vminfo1;
289 pal_vm_info_2_u_t vminfo2;
290 struct ia64_pal_retval result;
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;
306 static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
308 struct ia64_pal_retval result;
309 unsigned long in0, in1, in2, in3;
311 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
313 result.status = ia64_pal_vm_info(in1, in2,
314 (pal_tc_info_u_t *)&result.v1, &result.v2);
319 static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
322 struct exit_ctl_data *p;
324 p = kvm_get_exit_data(vcpu);
325 if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
326 index = p->u.pal_data.gr28;
331 static void prepare_for_halt(struct kvm_vcpu *vcpu)
333 vcpu->arch.timer_pending = 1;
334 vcpu->arch.timer_fired = 0;
337 static struct ia64_pal_retval pal_perf_mon_info(struct kvm_vcpu *vcpu)
340 unsigned long in0, in1, in2, in3, r9;
341 unsigned long pm_buffer[16];
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);
347 printk(KERN_DEBUG"PAL_PERF_MON_INFO fails ret=%ld\n", status);
350 memcpy((void *)in1, pm_buffer, sizeof(pm_buffer));
352 status = PAL_STATUS_EINVAL;
353 printk(KERN_WARNING"Invalid parameters "
354 "for PAL call:0x%lx!\n", in0);
357 return (struct ia64_pal_retval){status, r9, 0, 0};
360 static struct ia64_pal_retval pal_halt_info(struct kvm_vcpu *vcpu)
362 unsigned long in0, in1, in2, in3;
364 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
365 | (1UL << 61) | (1UL << 60);
367 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
369 memcpy((void *)in1, &res, sizeof(res));
372 status = PAL_STATUS_EINVAL;
373 printk(KERN_WARNING"Invalid parameters "
374 "for PAL call:0x%lx!\n", in0);
377 return (struct ia64_pal_retval){status, 0, 0, 0};
380 static struct ia64_pal_retval pal_mem_attrib(struct kvm_vcpu *vcpu)
385 status = ia64_pal_mem_attrib(&r9);
387 return (struct ia64_pal_retval){status, r9, 0, 0};
390 static void remote_pal_prefetch_visibility(void *v)
392 s64 trans_type = (s64)v;
393 ia64_pal_prefetch_visibility(trans_type);
396 static struct ia64_pal_retval pal_prefetch_visibility(struct kvm_vcpu *vcpu)
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,
407 /* Unnecessary on remote processor for other vcpus!*/
413 static void remote_pal_mc_drain(void *v)
418 static struct ia64_pal_retval pal_get_brand_info(struct kvm_vcpu *vcpu)
420 struct ia64_pal_retval result = {0, 0, 0, 0};
421 unsigned long in0, in1, in2, in3;
423 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
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);
431 result.status = PAL_STATUS_REQUIRES_MEMORY;
432 printk(KERN_WARNING"Invalid parameters for "
433 "PAL call:0x%lx!\n", in0);
439 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
443 struct ia64_pal_retval result;
446 gr28 = kvm_get_pal_call_index(vcpu);
448 case PAL_CACHE_FLUSH:
449 result = pal_cache_flush(vcpu);
452 result = pal_mem_attrib(vcpu);
454 case PAL_CACHE_SUMMARY:
455 result = pal_cache_summary(vcpu);
457 case PAL_PERF_MON_INFO:
458 result = pal_perf_mon_info(vcpu);
461 result = pal_halt_info(vcpu);
465 INIT_PAL_STATUS_SUCCESS(result);
466 prepare_for_halt(vcpu);
467 if (kvm_highest_pending_irq(vcpu) == -1)
468 ret = kvm_emulate_halt(vcpu);
472 case PAL_PREFETCH_VISIBILITY:
473 result = pal_prefetch_visibility(vcpu);
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);
482 case PAL_FREQ_RATIOS:
483 result = pal_freq_ratios(vcpu);
487 result = pal_freq_base(vcpu);
490 case PAL_LOGICAL_TO_PHYSICAL :
491 result = pal_logical_to_physica(vcpu);
494 case PAL_VM_SUMMARY :
495 result = pal_vm_summary(vcpu);
499 result = pal_vm_info(vcpu);
501 case PAL_PLATFORM_ADDR :
502 result = pal_platform_addr(vcpu);
505 result = pal_cache_info(vcpu);
508 INIT_PAL_STATUS_SUCCESS(result);
509 result.v1 = (1L << 32) | 1L;
511 case PAL_REGISTER_INFO:
512 result = pal_register_info(vcpu);
514 case PAL_VM_PAGE_SIZE:
515 result.status = ia64_pal_vm_page_size(&result.v0,
519 result.status = ia64_pal_rse_info(&result.v0,
520 (pal_hints_u_t *)&result.v1);
522 case PAL_PROC_GET_FEATURES:
523 result = pal_proc_get_features(vcpu);
526 result.status = ia64_pal_debug_info(&result.v0,
530 result.status = ia64_pal_version(
531 (pal_version_u_t *)&result.v0,
532 (pal_version_u_t *)&result.v1);
535 result.status = PAL_STATUS_SUCCESS;
536 result.v0 = vcpu->vcpu_id;
539 result = pal_get_brand_info(vcpu);
542 case PAL_CACHE_SHARED_INFO:
543 INIT_PAL_STATUS_UNIMPLEMENTED(result);
546 INIT_PAL_STATUS_UNIMPLEMENTED(result);
547 printk(KERN_WARNING"kvm: Unsupported pal call,"
548 " index:0x%lx\n", gr28);
550 set_pal_result(vcpu, result);
554 static 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)
560 unsigned long r9 = 0;
561 unsigned long r10 = 0;
568 status = ia64_sal_freq_base(in1, &r9, &r10);
570 case SAL_PCI_CONFIG_READ:
571 printk(KERN_WARNING"kvm: Not allowed to call here!"
572 " SAL_PCI_CONFIG_READ\n");
574 case SAL_PCI_CONFIG_WRITE:
575 printk(KERN_WARNING"kvm: Not allowed to call here!"
576 " SAL_PCI_CONFIG_WRITE\n");
578 case SAL_SET_VECTORS:
579 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
580 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
583 kvm->arch.rdv_sal_data.boot_ip = in2;
584 kvm->arch.rdv_sal_data.boot_gp = in3;
586 printk("Rendvous called! iip:%lx\n\n", in2);
588 printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
589 "ignored...\n", in1);
591 case SAL_GET_STATE_INFO:
596 case SAL_GET_STATE_INFO_SIZE:
597 /* Return a dummy size. */
601 case SAL_CLEAR_STATE_INFO:
606 "kvm: called SAL_MC_RENDEZ. ignored...\n");
608 case SAL_MC_SET_PARAMS:
610 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
612 case SAL_CACHE_FLUSH:
615 This method is faster but has a side
616 effect on other vcpu running on
618 status = ia64_sal_cache_flush(in1);
620 /*Maybe need to implement the method
621 without side effect!*/
627 "kvm: called SAL_CACHE_INIT. ignored...\n");
631 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
634 printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
635 " index:%ld\n", index);
639 return ((struct sal_ret_values) {status, r9, r10, r11});
642 static 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){
645 struct exit_ctl_data *p;
647 p = kvm_get_exit_data(vcpu);
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;
665 void kvm_sal_emul(struct kvm_vcpu *vcpu)
668 struct sal_ret_values result;
669 u64 index, in1, in2, in3, in4, in5, in6, in7;
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,
675 set_sal_result(vcpu, result);