Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/ia64/kvm/kvm_fw.c
10817 views
1
/*
2
* PAL/SAL call delegation
3
*
4
* Copyright (c) 2004 Li Susie <[email protected]>
5
* Copyright (c) 2005 Yu Ke <[email protected]>
6
* Copyright (c) 2007 Xiantao Zhang <[email protected]>
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>
24
#include <asm/sn/addrs.h>
25
#include <asm/sn/clksupport.h>
26
#include <asm/sn/shub_mmr.h>
27
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
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;
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
72
static 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->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
85
static 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->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
97
struct cache_flush_args {
98
u64 cache_type;
99
u64 operation;
100
u64 progress;
101
long status;
102
};
103
104
cpumask_t cpu_cache_coherent_map;
105
106
static 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
118
static 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,
136
(void *)&args, 1);
137
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
164
struct 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
173
static 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
194
/*
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
*/
199
static 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
214
static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
215
{
216
struct ia64_pal_retval result;
217
218
PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
219
220
if (vcpu->kvm->arch.is_sn2)
221
sn2_patch_itc_freq_ratios(&result);
222
223
return result;
224
}
225
226
static 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
234
static 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
243
static 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
256
static 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
268
static 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
285
static 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
306
static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
307
{
308
struct ia64_pal_retval result;
309
unsigned long in0, in1, in2, in3;
310
311
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);
315
316
return result;
317
}
318
319
static 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->exit_reason == EXIT_REASON_PAL_CALL)
326
index = p->u.pal_data.gr28;
327
328
return index;
329
}
330
331
static void prepare_for_halt(struct kvm_vcpu *vcpu)
332
{
333
vcpu->arch.timer_pending = 1;
334
vcpu->arch.timer_fired = 0;
335
}
336
337
static 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
360
static 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
380
static 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
390
static void remote_pal_prefetch_visibility(void *v)
391
{
392
s64 trans_type = (s64)v;
393
ia64_pal_prefetch_visibility(trans_type);
394
}
395
396
static 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
413
static void remote_pal_mc_drain(void *v)
414
{
415
ia64_pal_mc_drain();
416
}
417
418
static 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
439
int 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);
447
switch (gr28) {
448
case PAL_CACHE_FLUSH:
449
result = pal_cache_flush(vcpu);
450
break;
451
case PAL_MEM_ATTRIB:
452
result = pal_mem_attrib(vcpu);
453
break;
454
case PAL_CACHE_SUMMARY:
455
result = pal_cache_summary(vcpu);
456
break;
457
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;
463
case PAL_HALT_LIGHT:
464
{
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);
469
}
470
break;
471
472
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
482
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;
511
case PAL_REGISTER_INFO:
512
result = pal_register_info(vcpu);
513
break;
514
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);
533
break;
534
case PAL_FIXED_ADDR:
535
result.status = PAL_STATUS_SUCCESS;
536
result.v0 = vcpu->vcpu_id;
537
break;
538
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;
545
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
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)
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
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){
644
645
struct exit_ctl_data *p;
646
647
p = kvm_get_exit_data(vcpu);
648
649
if (p->exit_reason == EXIT_REASON_SAL_CALL) {
650
*in0 = p->u.sal_data.in0;
651
*in1 = p->u.sal_data.in1;
652
*in2 = p->u.sal_data.in2;
653
*in3 = p->u.sal_data.in3;
654
*in4 = p->u.sal_data.in4;
655
*in5 = p->u.sal_data.in5;
656
*in6 = p->u.sal_data.in6;
657
*in7 = p->u.sal_data.in7;
658
return ;
659
}
660
*in0 = 0;
661
}
662
663
void kvm_sal_emul(struct kvm_vcpu *vcpu)
664
{
665
666
struct sal_ret_values result;
667
u64 index, in1, in2, in3, in4, in5, in6, in7;
668
669
kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
670
&in3, &in4, &in5, &in6, &in7);
671
result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
672
in4, in5, in6, in7);
673
set_sal_result(vcpu, result);
674
}
675
676