aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/ia64/hypercall.c
blob: 64947ac59c948e4745b9df9c91e540316ed9fd22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Hypercall implementations
 * 
 * Copyright (C) 2005 Hewlett-Packard Co.
 *	Dan Magenheimer (dan.magenheimer@hp.com)
 *
 */

#include <xen/config.h>
#include <xen/sched.h>

#include <linux/efi.h>	/* FOR EFI_UNIMPLEMENTED */
#include <asm/sal.h>	/* FOR struct ia64_sal_retval */

#include <asm/vcpu.h>
#include <asm/dom_fw.h>

extern unsigned long translate_domain_mpaddr(unsigned long);
extern struct ia64_sal_retval pal_emulator_static(UINT64);
extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64);

int
ia64_hypercall (struct pt_regs *regs)
{
	struct vcpu *v = (struct domain *) current;
	struct ia64_sal_retval x;
	unsigned long *tv, *tc;

	switch (regs->r2) {
	    case FW_HYPERCALL_PAL_CALL:
		//printf("*** PAL hypercall: index=%d\n",regs->r28);
		//FIXME: This should call a C routine
#if 1
		// This is very conservative, but avoids a possible
		// (and deadly) freeze in paravirtualized domains due
		// to a yet-to-be-found bug where pending_interruption
		// is zero when it shouldn't be. Since PAL is called
		// in the idle loop, this should resolve it
		v->vcpu_info->arch.pending_interruption = 1;
#endif
		x = pal_emulator_static(regs->r28);
		if (regs->r28 == PAL_HALT_LIGHT) {
			do_sched_op(SCHEDOP_yield);
			//break;
		}
		regs->r8 = x.status; regs->r9 = x.v0;
		regs->r10 = x.v1; regs->r11 = x.v2;
		break;
	    case FW_HYPERCALL_SAL_CALL:
		x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
			vcpu_get_gr(v,34),vcpu_get_gr(v,35),
			vcpu_get_gr(v,36),vcpu_get_gr(v,37),
			vcpu_get_gr(v,38),vcpu_get_gr(v,39));
		regs->r8 = x.status; regs->r9 = x.v0;
		regs->r10 = x.v1; regs->r11 = x.v2;
		break;
	    case FW_HYPERCALL_EFI_RESET_SYSTEM:
		printf("efi.reset_system called ");
		if (current->domain == dom0) {
			printf("(by dom0)\n ");
			(*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
		}
#ifdef DOMU_AUTO_RESTART
		else {
			reconstruct_domU(current);
			return 0;  // don't increment ip!
		}
#else	
		printf("(not supported for non-0 domain)\n");
		regs->r8 = EFI_UNSUPPORTED;
#endif
		break;
	    case FW_HYPERCALL_EFI_GET_TIME:
		tv = vcpu_get_gr(v,32);
		tc = vcpu_get_gr(v,33);
		//printf("efi_get_time(%p,%p) called...",tv,tc);
		tv = __va(translate_domain_mpaddr(tv));
		if (tc) tc = __va(translate_domain_mpaddr(tc));
		regs->r8 = (*efi.get_time)(tv,tc);
		//printf("and returns %lx\n",regs->r8);
		break;
	    case FW_HYPERCALL_EFI_SET_TIME:
	    case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
	    case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
		// FIXME: need fixes in efi.h from 2.6.9
	    case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
		// FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
		// SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS 
		// POINTER ARGUMENTS WILL BE VIRTUAL!!
	    case FW_HYPERCALL_EFI_GET_VARIABLE:
		// FIXME: need fixes in efi.h from 2.6.9
	    case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
	    case FW_HYPERCALL_EFI_SET_VARIABLE:
	    case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
		// FIXME: need fixes in efi.h from 2.6.9
		regs->r8 = EFI_UNSUPPORTED;
		break;
	    case 0xffff: // test dummy hypercall
		regs->r8 = dump_privop_counts_to_user(
			vcpu_get_gr(v,32),
			vcpu_get_gr(v,33));
		break;
	    case 0xfffe: // test dummy hypercall
		regs->r8 = zero_privop_counts_to_user(
			vcpu_get_gr(v,32),
			vcpu_get_gr(v,33));
		break;
	    case 0xfffd: // test dummy hypercall
		regs->r8 = launch_domainU(
			vcpu_get_gr(v,32));
		break;
	    case 0xfffc: // test dummy hypercall
		regs->r8 = domU_staging_write_32(
			vcpu_get_gr(v,32),
			vcpu_get_gr(v,33),
			vcpu_get_gr(v,34),
			vcpu_get_gr(v,35),
			vcpu_get_gr(v,36));
		break;
	    case 0xfffb: // test dummy hypercall
		regs->r8 = domU_staging_read_8(vcpu_get_gr(v,32));
		break;

	    case __HYPERVISOR_dom0_op:
		regs->r8 = do_dom0_op(regs->r14);
		break;

	    case __HYPERVISOR_dom_mem_op:
		/* regs->r8 = do_dom_mem_op(regs->r14, regs->r15, regs->r16, regs->r17, regs->r18); */
		/* we don't handle reservations; just return success */
		regs->r8 = regs->r16;
		break;

	    case __HYPERVISOR_event_channel_op:
		regs->r8 = do_event_channel_op(regs->r14);
		break;

	    case __HYPERVISOR_console_io:
		regs->r8 = do_console_io(regs->r14, regs->r15, regs->r16);
		break;

	    default:
		printf("unknown hypercall %x\n", regs->r2);
		regs->r8 = (unsigned long)-1;
	}
	return 1;
}