ia64/xen-unstable

view xen/arch/ia64/vmx/sioemu.c @ 17200:16f6435a9d07

[IA64] get_wallclock also returns NOW value.

At least sched_poll hypercall needs to have access to the NOW value
(time since boot). This patch makes NOW available from sioemu.

Signed-off-by: Tristan Gingold <tgingold@free.fr>
author Alex Williamson <alex.williamson@hp.com>
date Mon Mar 10 11:10:46 2008 -0600 (2008-03-10)
parents f40a07c00209
children e768be7bf561
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2 /*
3 * sioemu.c: Self IO emulation - hypercall and return.
4 * Copyright (c) 2008, Tristan Gingold <tgingold@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 */
20 #include <asm/vcpu.h>
21 #include <asm/vmx_vcpu.h>
22 #include <asm/sioemu.h>
23 #include <public/arch-ia64/sioemu.h>
24 #include <asm/dom_fw.h>
25 #include <asm/debugger.h>
26 #include <asm/sal.h>
27 #include <asm/vlsapic.h>
29 static void
30 sioemu_save_regs (VCPU *vcpu)
31 {
32 REGS *regs = vcpu_regs(vcpu);
34 vcpu->arch.arch_vmx.stub_saved[0] = regs->r16;
35 vcpu->arch.arch_vmx.stub_saved[1] = regs->r17;
36 vcpu->arch.arch_vmx.stub_saved[2] = regs->r18;
37 vcpu->arch.arch_vmx.stub_saved[3] = regs->r19;
38 vcpu->arch.arch_vmx.stub_saved[4] = regs->r20;
39 vcpu->arch.arch_vmx.stub_saved[5] = regs->r21;
40 vcpu->arch.arch_vmx.stub_saved[6] = regs->r22;
41 vcpu->arch.arch_vmx.stub_saved[7] = regs->r23;
42 vcpu->arch.arch_vmx.stub_saved[8] = regs->r24;
43 vcpu->arch.arch_vmx.stub_saved[9] = regs->r25;
44 vcpu->arch.arch_vmx.stub_saved[10] = regs->r26;
45 vcpu->arch.arch_vmx.stub_saved[11] = regs->r27;
46 vcpu->arch.arch_vmx.stub_saved[12] = regs->r28;
47 vcpu->arch.arch_vmx.stub_saved[13] = regs->r29;
48 vcpu->arch.arch_vmx.stub_saved[14] = regs->r30;
49 vcpu->arch.arch_vmx.stub_saved[15] = regs->r31;
50 vcpu->arch.arch_vmx.stub_nats =
51 (regs->eml_unat >> IA64_PT_REGS_R16_SLOT) & 0xffff;
52 }
54 static void
55 sioemu_restore_regs (VCPU *vcpu)
56 {
57 REGS *regs = vcpu_regs(vcpu);
59 /* First restore registers. */
60 regs->cr_iip = regs->r28;
61 regs->cr_ifs = regs->r30;
62 vmx_vcpu_set_psr (vcpu, regs->r29);
64 regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT);
65 regs->eml_unat |= vcpu->arch.arch_vmx.stub_nats << IA64_PT_REGS_R16_SLOT;
67 regs->r16 = vcpu->arch.arch_vmx.stub_saved[0];
68 regs->r17 = vcpu->arch.arch_vmx.stub_saved[1];
69 regs->r18 = vcpu->arch.arch_vmx.stub_saved[2];
70 regs->r19 = vcpu->arch.arch_vmx.stub_saved[3];
71 regs->r20 = vcpu->arch.arch_vmx.stub_saved[4];
72 regs->r21 = vcpu->arch.arch_vmx.stub_saved[5];
73 regs->r22 = vcpu->arch.arch_vmx.stub_saved[6];
74 regs->r23 = vcpu->arch.arch_vmx.stub_saved[7];
75 regs->r24 = vcpu->arch.arch_vmx.stub_saved[8];
76 regs->r25 = vcpu->arch.arch_vmx.stub_saved[9];
77 regs->r26 = vcpu->arch.arch_vmx.stub_saved[10];
78 regs->r27 = vcpu->arch.arch_vmx.stub_saved[11];
79 regs->r28 = vcpu->arch.arch_vmx.stub_saved[12];
80 regs->r29 = vcpu->arch.arch_vmx.stub_saved[13];
81 regs->r30 = vcpu->arch.arch_vmx.stub_saved[14];
82 regs->r31 = vcpu->arch.arch_vmx.stub_saved[15];
84 }
86 static REGS *
87 sioemu_deliver (void)
88 {
89 VCPU *vcpu = current;
90 REGS *regs = vcpu_regs(vcpu);
91 unsigned long psr = vmx_vcpu_get_psr(vcpu);
93 if (vcpu->vcpu_info->evtchn_upcall_mask)
94 panic_domain (NULL, "sioemu_deliver: aleady in stub mode\n");
96 /* All cleared, but keep BN. */
97 vmx_vcpu_set_psr(vcpu, IA64_PSR_MC | (psr & IA64_PSR_BN));
99 /* Save registers. */
100 sioemu_save_regs (vcpu);
102 /* Context. */
103 regs->r28 = regs->cr_iip;
104 regs->r29 = psr;
105 regs->r30 = regs->cr_ifs;
107 regs->cr_ifs = 0; // pre-cover
109 regs->cr_iip = vcpu->arch.event_callback_ip;
110 regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT);
112 /* Parameters. */
113 regs->r16 = 0;
114 regs->r17 = vcpu->arch.arch_vmx.stub_buffer;
116 /* Mask events. */
117 vcpu->vcpu_info->evtchn_upcall_mask = 1;
119 debugger_event(XEN_IA64_DEBUG_ON_EVENT);
121 return regs;
122 }
124 void
125 sioemu_callback_return (void)
126 {
127 VCPU *vcpu = current;
128 REGS *regs = vcpu_regs(vcpu);
129 u64 cmd = regs->r16;
130 u64 arg1 = regs->r19;
131 u64 arg2 = regs->r20;
132 u64 arg3 = regs->r21;
134 if ((cmd & ~0x1UL) != 0)
135 panic_domain (NULL, "sioemu_callback_return: bad operation (%lx)\n",
136 cmd);
138 /* First restore registers. */
139 regs->cr_iip = regs->r28;
140 regs->cr_ifs = regs->r30;
141 vmx_vcpu_set_psr (vcpu, regs->r29);
143 sioemu_restore_regs (vcpu);
145 /* Unmask events. */
146 vcpu->vcpu_info->evtchn_upcall_mask = 0;
148 /* Then apply commands. */
149 if (cmd & 1) {
150 emulate_io_update (vcpu, arg1, arg2, arg3);
151 }
152 }
154 void
155 sioemu_deliver_event (void)
156 {
157 REGS *regs;
159 regs = sioemu_deliver ();
160 regs->r16 = SIOEMU_CB_EVENT;
161 }
163 void
164 sioemu_io_emulate (unsigned long padr, unsigned long data,
165 unsigned long data1, unsigned long word)
166 {
167 REGS *regs;
169 regs = sioemu_deliver ();
170 regs->r16 = SIOEMU_CB_IO_EMULATE;
171 regs->r19 = padr;
172 regs->r20 = data;
173 regs->r21 = data1;
174 regs->r22 = word;
175 }
177 void
178 sioemu_wakeup_vcpu (int vcpu_id)
179 {
180 REGS *regs;
182 regs = sioemu_deliver();
183 regs->r16 = SIOEMU_CB_WAKEUP_VCPU;
184 regs->r19 = vcpu_id;
185 }
187 void
188 sioemu_sal_assist (struct vcpu *v)
189 {
190 REGS *regs;
192 regs = sioemu_deliver();
193 regs->r16 = SIOEMU_CB_SAL_ASSIST;
194 }
196 static int
197 sioemu_add_io_physmap (struct domain *d, unsigned long start,
198 unsigned long size, unsigned long type)
199 {
200 unsigned long i;
201 int res;
203 /* Check type. */
204 if (type == 0 || (type & GPFN_IO_MASK) != type)
205 return -EINVAL;
206 if ((start & (PAGE_SIZE -1)) || (size & (PAGE_SIZE - 1)))
207 return -EINVAL;
209 /* Check area is currently unassigned. */
210 for (i = start; i < start + size; i += PAGE_SIZE) {
211 if (____lookup_domain_mpa(d, i) != INVALID_MFN)
212 return -EBUSY;
213 }
215 /* Set. */
216 for (i = start; i < start + size; i += PAGE_SIZE) {
217 res = __assign_domain_page(d, i, type, ASSIGN_writable);
218 if (res != 0)
219 return res;
220 }
222 return 0;
223 }
225 void
226 sioemu_hypercall (struct pt_regs *regs)
227 {
228 //printk ("sioemu_hypercall: r2=%lx r8=%lx r9=%lx\n",
229 // regs->r2, regs->r8, regs->r9);
231 if (current->vcpu_info->evtchn_upcall_mask == 0)
232 panic_domain(NULL, "sioemu_hypercall: not in stub mode\n");
234 switch (regs->r2 & FW_HYPERCALL_NUM_MASK_LOW)
235 {
236 case SIOEMU_HYPERCALL_SET_CALLBACK:
237 current->arch.event_callback_ip = regs->r8;
238 current->arch.arch_vmx.stub_buffer = regs->r9;
239 break;
240 case SIOEMU_HYPERCALL_START_FW:
241 regs->cr_iip = regs->r8;
242 vmx_vcpu_set_psr(current, regs->r9);
243 current->vcpu_info->evtchn_upcall_mask = 0;
244 break;
245 case SIOEMU_HYPERCALL_ADD_IO_PHYSMAP:
246 regs->r8 = sioemu_add_io_physmap(current->domain,
247 regs->r8, regs->r9, regs->r10);
248 break;
249 case SIOEMU_HYPERCALL_GET_TIME:
250 {
251 uint64_t sec, nsec, now;
252 get_wallclock(&sec, &nsec, &now);
253 regs->r8 = (sec << 30) + nsec;
254 regs->r9 = now;
255 break;
256 }
257 case SIOEMU_HYPERCALL_GET_REGS:
258 sioemu_restore_regs(current);
259 break;
260 case SIOEMU_HYPERCALL_SET_REGS:
261 sioemu_save_regs(current);
262 break;
263 case SIOEMU_HYPERCALL_FLUSH_CACHE:
264 regs->r8 = ia64_sal_cache_flush(regs->r8);
265 break;
266 case SIOEMU_HYPERCALL_FREQ_BASE:
267 regs->r8 = ia64_sal_freq_base(regs->r8, &regs->r9, &regs->r10);
268 break;
269 case SIOEMU_HYPERCALL_DELIVER_INT:
270 regs->r8 = vlsapic_deliver_int(current->domain,
271 regs->r8, regs->r9, regs->r10);
272 break;
273 case SIOEMU_HYPERCALL_CALLBACK_RETURN:
274 regs->r2 = regs->r27;
275 sioemu_callback_return ();
276 vcpu_decrement_iip(current);
277 break;
278 default:
279 panic_domain (NULL, "bad sioemu hypercall %lx\n", regs->r2);
280 break;
281 }
282 }