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>
33 * Handy macros to make sure that the PAL return values start out
34 * as something meaningful.
36 #define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
38 x.status = PAL_STATUS_UNIMPLEMENTED; \
44 #define INIT_PAL_STATUS_SUCCESS(x) \
46 x.status = PAL_STATUS_SUCCESS; \
52 static void kvm_get_pal_call_data(struct kvm_vcpu
*vcpu
,
53 u64
*gr28
, u64
*gr29
, u64
*gr30
, u64
*gr31
) {
54 struct exit_ctl_data
*p
;
57 p
= &vcpu
->arch
.exit_data
;
58 if (p
->exit_reason
== EXIT_REASON_PAL_CALL
) {
59 *gr28
= p
->u
.pal_data
.gr28
;
60 *gr29
= p
->u
.pal_data
.gr29
;
61 *gr30
= p
->u
.pal_data
.gr30
;
62 *gr31
= p
->u
.pal_data
.gr31
;
66 printk(KERN_DEBUG
"Failed to get vcpu pal data!!!\n");
69 static void set_pal_result(struct kvm_vcpu
*vcpu
,
70 struct ia64_pal_retval result
) {
72 struct exit_ctl_data
*p
;
74 p
= kvm_get_exit_data(vcpu
);
75 if (p
&& p
->exit_reason
== EXIT_REASON_PAL_CALL
) {
76 p
->u
.pal_data
.ret
= result
;
79 INIT_PAL_STATUS_UNIMPLEMENTED(p
->u
.pal_data
.ret
);
82 static void set_sal_result(struct kvm_vcpu
*vcpu
,
83 struct sal_ret_values result
) {
84 struct exit_ctl_data
*p
;
86 p
= kvm_get_exit_data(vcpu
);
87 if (p
&& p
->exit_reason
== EXIT_REASON_SAL_CALL
) {
88 p
->u
.sal_data
.ret
= result
;
91 printk(KERN_WARNING
"Failed to set sal result!!\n");
94 struct cache_flush_args
{
101 cpumask_t cpu_cache_coherent_map
;
103 static void remote_pal_cache_flush(void *data
)
105 struct cache_flush_args
*args
= data
;
107 u64 progress
= args
->progress
;
109 status
= ia64_pal_cache_flush(args
->cache_type
, args
->operation
,
112 args
->status
= status
;
115 static struct ia64_pal_retval
pal_cache_flush(struct kvm_vcpu
*vcpu
)
117 u64 gr28
, gr29
, gr30
, gr31
;
118 struct ia64_pal_retval result
= {0, 0, 0, 0};
119 struct cache_flush_args args
= {0, 0, 0, 0};
122 gr28
= gr29
= gr30
= gr31
= 0;
123 kvm_get_pal_call_data(vcpu
, &gr28
, &gr29
, &gr30
, &gr31
);
126 printk(KERN_ERR
"vcpu:%p called cache_flush error!\n", vcpu
);
128 /* Always call Host Pal in int=1 */
129 gr30
&= ~PAL_CACHE_FLUSH_CHK_INTRS
;
130 args
.cache_type
= gr29
;
131 args
.operation
= gr30
;
132 smp_call_function(remote_pal_cache_flush
,
134 if (args
.status
!= 0)
135 printk(KERN_ERR
"pal_cache_flush error!,"
136 "status:0x%lx\n", args
.status
);
138 * Call Host PAL cache flush
139 * Clear psr.ic when call PAL_CACHE_FLUSH
142 result
.status
= ia64_pal_cache_flush(gr29
, gr30
, &result
.v1
,
144 local_irq_restore(psr
);
145 if (result
.status
!= 0)
146 printk(KERN_ERR
"vcpu:%p crashed due to cache_flush err:%ld"
148 vcpu
, result
.status
, gr29
, gr30
);
151 if (gr29
== PAL_CACHE_TYPE_COHERENT
) {
152 cpus_setall(vcpu
->arch
.cache_coherent_map
);
153 cpu_clear(vcpu
->cpu
, vcpu
->arch
.cache_coherent_map
);
154 cpus_setall(cpu_cache_coherent_map
);
155 cpu_clear(vcpu
->cpu
, cpu_cache_coherent_map
);
161 struct ia64_pal_retval
pal_cache_summary(struct kvm_vcpu
*vcpu
)
164 struct ia64_pal_retval result
;
166 PAL_CALL(result
, PAL_CACHE_SUMMARY
, 0, 0, 0);
170 static struct ia64_pal_retval
pal_freq_base(struct kvm_vcpu
*vcpu
)
173 struct ia64_pal_retval result
;
175 PAL_CALL(result
, PAL_FREQ_BASE
, 0, 0, 0);
178 * PAL_FREQ_BASE may not be implemented in some platforms,
181 if (result
.v0
== 0) {
182 result
.status
= ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM
,
191 static struct ia64_pal_retval
pal_freq_ratios(struct kvm_vcpu
*vcpu
)
194 struct ia64_pal_retval result
;
196 PAL_CALL(result
, PAL_FREQ_RATIOS
, 0, 0, 0);
200 static struct ia64_pal_retval
pal_logical_to_physica(struct kvm_vcpu
*vcpu
)
202 struct ia64_pal_retval result
;
204 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
208 static struct ia64_pal_retval
pal_platform_addr(struct kvm_vcpu
*vcpu
)
211 struct ia64_pal_retval result
;
213 INIT_PAL_STATUS_SUCCESS(result
);
217 static struct ia64_pal_retval
pal_proc_get_features(struct kvm_vcpu
*vcpu
)
220 struct ia64_pal_retval result
= {0, 0, 0, 0};
221 long in0
, in1
, in2
, in3
;
223 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
224 result
.status
= ia64_pal_proc_get_features(&result
.v0
, &result
.v1
,
230 static struct ia64_pal_retval
pal_register_info(struct kvm_vcpu
*vcpu
)
233 struct ia64_pal_retval result
= {0, 0, 0, 0};
234 long in0
, in1
, in2
, in3
;
236 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
237 result
.status
= ia64_pal_register_info(in1
, &result
.v1
, &result
.v2
);
242 static struct ia64_pal_retval
pal_cache_info(struct kvm_vcpu
*vcpu
)
245 pal_cache_config_info_t ci
;
247 unsigned long in0
, in1
, in2
, in3
, r9
, r10
;
249 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
250 status
= ia64_pal_cache_config_info(in1
, in2
, &ci
);
251 r9
= ci
.pcci_info_1
.pcci1_data
;
252 r10
= ci
.pcci_info_2
.pcci2_data
;
253 return ((struct ia64_pal_retval
){status
, r9
, r10
, 0});
256 #define GUEST_IMPL_VA_MSB 59
257 #define GUEST_RID_BITS 18
259 static struct ia64_pal_retval
pal_vm_summary(struct kvm_vcpu
*vcpu
)
262 pal_vm_info_1_u_t vminfo1
;
263 pal_vm_info_2_u_t vminfo2
;
264 struct ia64_pal_retval result
;
266 PAL_CALL(result
, PAL_VM_SUMMARY
, 0, 0, 0);
267 if (!result
.status
) {
268 vminfo1
.pvi1_val
= result
.v0
;
269 vminfo1
.pal_vm_info_1_s
.max_itr_entry
= 8;
270 vminfo1
.pal_vm_info_1_s
.max_dtr_entry
= 8;
271 result
.v0
= vminfo1
.pvi1_val
;
272 vminfo2
.pal_vm_info_2_s
.impl_va_msb
= GUEST_IMPL_VA_MSB
;
273 vminfo2
.pal_vm_info_2_s
.rid_size
= GUEST_RID_BITS
;
274 result
.v1
= vminfo2
.pvi2_val
;
280 static struct ia64_pal_retval
pal_vm_info(struct kvm_vcpu
*vcpu
)
282 struct ia64_pal_retval result
;
283 unsigned long in0
, in1
, in2
, in3
;
285 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
287 result
.status
= ia64_pal_vm_info(in1
, in2
,
288 (pal_tc_info_u_t
*)&result
.v1
, &result
.v2
);
293 static u64
kvm_get_pal_call_index(struct kvm_vcpu
*vcpu
)
296 struct exit_ctl_data
*p
;
298 p
= kvm_get_exit_data(vcpu
);
299 if (p
&& (p
->exit_reason
== EXIT_REASON_PAL_CALL
))
300 index
= p
->u
.pal_data
.gr28
;
305 static void prepare_for_halt(struct kvm_vcpu
*vcpu
)
307 vcpu
->arch
.timer_pending
= 1;
308 vcpu
->arch
.timer_fired
= 0;
311 static struct ia64_pal_retval
pal_perf_mon_info(struct kvm_vcpu
*vcpu
)
314 unsigned long in0
, in1
, in2
, in3
, r9
;
315 unsigned long pm_buffer
[16];
317 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
318 status
= ia64_pal_perf_mon_info(pm_buffer
,
319 (pal_perf_mon_info_u_t
*) &r9
);
321 printk(KERN_DEBUG
"PAL_PERF_MON_INFO fails ret=%ld\n", status
);
324 memcpy((void *)in1
, pm_buffer
, sizeof(pm_buffer
));
326 status
= PAL_STATUS_EINVAL
;
327 printk(KERN_WARNING
"Invalid parameters "
328 "for PAL call:0x%lx!\n", in0
);
331 return (struct ia64_pal_retval
){status
, r9
, 0, 0};
334 static struct ia64_pal_retval
pal_halt_info(struct kvm_vcpu
*vcpu
)
336 unsigned long in0
, in1
, in2
, in3
;
338 unsigned long res
= 1000UL | (1000UL << 16) | (10UL << 32)
339 | (1UL << 61) | (1UL << 60);
341 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
343 memcpy((void *)in1
, &res
, sizeof(res
));
346 status
= PAL_STATUS_EINVAL
;
347 printk(KERN_WARNING
"Invalid parameters "
348 "for PAL call:0x%lx!\n", in0
);
351 return (struct ia64_pal_retval
){status
, 0, 0, 0};
354 static struct ia64_pal_retval
pal_mem_attrib(struct kvm_vcpu
*vcpu
)
359 status
= ia64_pal_mem_attrib(&r9
);
361 return (struct ia64_pal_retval
){status
, r9
, 0, 0};
364 static void remote_pal_prefetch_visibility(void *v
)
366 s64 trans_type
= (s64
)v
;
367 ia64_pal_prefetch_visibility(trans_type
);
370 static struct ia64_pal_retval
pal_prefetch_visibility(struct kvm_vcpu
*vcpu
)
372 struct ia64_pal_retval result
= {0, 0, 0, 0};
373 unsigned long in0
, in1
, in2
, in3
;
374 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
375 result
.status
= ia64_pal_prefetch_visibility(in1
);
376 if (result
.status
== 0) {
377 /* Must be performed on all remote processors
378 in the coherence domain. */
379 smp_call_function(remote_pal_prefetch_visibility
,
381 /* Unnecessary on remote processor for other vcpus!*/
387 static void remote_pal_mc_drain(void *v
)
392 static struct ia64_pal_retval
pal_get_brand_info(struct kvm_vcpu
*vcpu
)
394 struct ia64_pal_retval result
= {0, 0, 0, 0};
395 unsigned long in0
, in1
, in2
, in3
;
397 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
399 if (in1
== 0 && in2
) {
400 char brand_info
[128];
401 result
.status
= ia64_pal_get_brand_info(brand_info
);
402 if (result
.status
== PAL_STATUS_SUCCESS
)
403 memcpy((void *)in2
, brand_info
, 128);
405 result
.status
= PAL_STATUS_REQUIRES_MEMORY
;
406 printk(KERN_WARNING
"Invalid parameters for "
407 "PAL call:0x%lx!\n", in0
);
413 int kvm_pal_emul(struct kvm_vcpu
*vcpu
, struct kvm_run
*run
)
417 struct ia64_pal_retval result
;
420 gr28
= kvm_get_pal_call_index(vcpu
);
422 case PAL_CACHE_FLUSH
:
423 result
= pal_cache_flush(vcpu
);
426 result
= pal_mem_attrib(vcpu
);
428 case PAL_CACHE_SUMMARY
:
429 result
= pal_cache_summary(vcpu
);
431 case PAL_PERF_MON_INFO
:
432 result
= pal_perf_mon_info(vcpu
);
435 result
= pal_halt_info(vcpu
);
439 INIT_PAL_STATUS_SUCCESS(result
);
440 prepare_for_halt(vcpu
);
441 if (kvm_highest_pending_irq(vcpu
) == -1)
442 ret
= kvm_emulate_halt(vcpu
);
446 case PAL_PREFETCH_VISIBILITY
:
447 result
= pal_prefetch_visibility(vcpu
);
450 result
.status
= ia64_pal_mc_drain();
451 /* FIXME: All vcpus likely call PAL_MC_DRAIN.
452 That causes the congestion. */
453 smp_call_function(remote_pal_mc_drain
, NULL
, 1);
456 case PAL_FREQ_RATIOS
:
457 result
= pal_freq_ratios(vcpu
);
461 result
= pal_freq_base(vcpu
);
464 case PAL_LOGICAL_TO_PHYSICAL
:
465 result
= pal_logical_to_physica(vcpu
);
468 case PAL_VM_SUMMARY
:
469 result
= pal_vm_summary(vcpu
);
473 result
= pal_vm_info(vcpu
);
475 case PAL_PLATFORM_ADDR
:
476 result
= pal_platform_addr(vcpu
);
479 result
= pal_cache_info(vcpu
);
482 INIT_PAL_STATUS_SUCCESS(result
);
483 result
.v1
= (1L << 32) | 1L;
485 case PAL_REGISTER_INFO
:
486 result
= pal_register_info(vcpu
);
488 case PAL_VM_PAGE_SIZE
:
489 result
.status
= ia64_pal_vm_page_size(&result
.v0
,
493 result
.status
= ia64_pal_rse_info(&result
.v0
,
494 (pal_hints_u_t
*)&result
.v1
);
496 case PAL_PROC_GET_FEATURES
:
497 result
= pal_proc_get_features(vcpu
);
500 result
.status
= ia64_pal_debug_info(&result
.v0
,
504 result
.status
= ia64_pal_version(
505 (pal_version_u_t
*)&result
.v0
,
506 (pal_version_u_t
*)&result
.v1
);
509 result
.status
= PAL_STATUS_SUCCESS
;
510 result
.v0
= vcpu
->vcpu_id
;
513 result
= pal_get_brand_info(vcpu
);
516 case PAL_CACHE_SHARED_INFO
:
517 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
520 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
521 printk(KERN_WARNING
"kvm: Unsupported pal call,"
522 " index:0x%lx\n", gr28
);
524 set_pal_result(vcpu
, result
);
528 static struct sal_ret_values
sal_emulator(struct kvm
*kvm
,
529 long index
, unsigned long in1
,
530 unsigned long in2
, unsigned long in3
,
531 unsigned long in4
, unsigned long in5
,
532 unsigned long in6
, unsigned long in7
)
534 unsigned long r9
= 0;
535 unsigned long r10
= 0;
542 status
= ia64_sal_freq_base(in1
, &r9
, &r10
);
544 case SAL_PCI_CONFIG_READ
:
545 printk(KERN_WARNING
"kvm: Not allowed to call here!"
546 " SAL_PCI_CONFIG_READ\n");
548 case SAL_PCI_CONFIG_WRITE
:
549 printk(KERN_WARNING
"kvm: Not allowed to call here!"
550 " SAL_PCI_CONFIG_WRITE\n");
552 case SAL_SET_VECTORS
:
553 if (in1
== SAL_VECTOR_OS_BOOT_RENDEZ
) {
554 if (in4
!= 0 || in5
!= 0 || in6
!= 0 || in7
!= 0) {
557 kvm
->arch
.rdv_sal_data
.boot_ip
= in2
;
558 kvm
->arch
.rdv_sal_data
.boot_gp
= in3
;
560 printk("Rendvous called! iip:%lx\n\n", in2
);
562 printk(KERN_WARNING
"kvm: CALLED SAL_SET_VECTORS %lu."
563 "ignored...\n", in1
);
565 case SAL_GET_STATE_INFO
:
570 case SAL_GET_STATE_INFO_SIZE
:
571 /* Return a dummy size. */
575 case SAL_CLEAR_STATE_INFO
:
580 "kvm: called SAL_MC_RENDEZ. ignored...\n");
582 case SAL_MC_SET_PARAMS
:
584 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
586 case SAL_CACHE_FLUSH
:
589 This method is faster but has a side
590 effect on other vcpu running on
592 status
= ia64_sal_cache_flush(in1
);
594 /*Maybe need to implement the method
595 without side effect!*/
601 "kvm: called SAL_CACHE_INIT. ignored...\n");
605 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
608 printk(KERN_WARNING
"kvm: called SAL_CALL with unknown index."
609 " index:%ld\n", index
);
613 return ((struct sal_ret_values
) {status
, r9
, r10
, r11
});
616 static void kvm_get_sal_call_data(struct kvm_vcpu
*vcpu
, u64
*in0
, u64
*in1
,
617 u64
*in2
, u64
*in3
, u64
*in4
, u64
*in5
, u64
*in6
, u64
*in7
){
619 struct exit_ctl_data
*p
;
621 p
= kvm_get_exit_data(vcpu
);
624 if (p
->exit_reason
== EXIT_REASON_SAL_CALL
) {
625 *in0
= p
->u
.sal_data
.in0
;
626 *in1
= p
->u
.sal_data
.in1
;
627 *in2
= p
->u
.sal_data
.in2
;
628 *in3
= p
->u
.sal_data
.in3
;
629 *in4
= p
->u
.sal_data
.in4
;
630 *in5
= p
->u
.sal_data
.in5
;
631 *in6
= p
->u
.sal_data
.in6
;
632 *in7
= p
->u
.sal_data
.in7
;
639 void kvm_sal_emul(struct kvm_vcpu
*vcpu
)
642 struct sal_ret_values result
;
643 u64 index
, in1
, in2
, in3
, in4
, in5
, in6
, in7
;
645 kvm_get_sal_call_data(vcpu
, &index
, &in1
, &in2
,
646 &in3
, &in4
, &in5
, &in6
, &in7
);
647 result
= sal_emulator(vcpu
->kvm
, index
, in1
, in2
, in3
,
649 set_sal_result(vcpu
, result
);