debuggers.hg

view xen/arch/ia64/vmx/sioemu.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 46f8fc57b1a4
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 struct sioemu_callback_info *
30 sioemu_deliver (void)
31 {
32 VCPU *vcpu = current;
33 REGS *regs = vcpu_regs(vcpu);
34 struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva;
35 unsigned long psr = vmx_vcpu_get_psr(vcpu);
37 if (vcpu->vcpu_info->evtchn_upcall_mask)
38 panic_domain (NULL, "sioemu_deliver: aleady in stub mode\n");
39 if (info == NULL)
40 panic_domain (NULL, "sioemu_deliver: set_callback not called\n");
42 /* All cleared, but keep BN. */
43 vmx_vcpu_set_psr(vcpu, IA64_PSR_MC | (psr & IA64_PSR_BN));
45 /* Set info. */
46 info->ip = regs->cr_iip;
47 info->psr = psr;
48 info->ifs = regs->cr_ifs;
49 info->nats = (((regs->eml_unat >> IA64_PT_REGS_R8_SLOT) & 0x0f) << 8)
50 | (((regs->eml_unat >> IA64_PT_REGS_R2_SLOT) & 1) << 2);
51 info->r8 = regs->r8;
52 info->r9 = regs->r9;
53 info->r10 = regs->r10;
54 info->r11 = regs->r11;
55 info->r2 = regs->r2;
57 regs->cr_ifs = 0; // pre-cover
58 regs->cr_iip = vcpu->arch.event_callback_ip;
59 regs->eml_unat &= ~(1UL << IA64_PT_REGS_R8_SLOT);
60 regs->r8 = vcpu->arch.arch_vmx.sioemu_info_gpa;
62 /* Mask events. */
63 vcpu->vcpu_info->evtchn_upcall_mask = 1;
65 debugger_event(XEN_IA64_DEBUG_ON_EVENT);
67 return info;
68 }
70 static void
71 sioemu_callback_return (void)
72 {
73 VCPU *vcpu = current;
74 REGS *regs = vcpu_regs(vcpu);
75 struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva;
77 if (info == NULL)
78 panic_domain (NULL, "sioemu_deliver: set_callback not called\n");
79 if ((info->cause & ~0x1UL) != 0)
80 panic_domain (NULL, "sioemu_callback_return: bad operation (%lx)\n",
81 info->cause);
83 /* First restore registers. */
84 regs->cr_iip = info->ip;
85 regs->cr_ifs = info->ifs;
86 vmx_vcpu_set_psr (vcpu, info->psr);
87 regs->r8 = info->r8;
88 regs->r9 = info->r9;
89 regs->r10 = info->r10;
90 regs->r11 = info->r11;
91 regs->r2 = info->r2;
92 regs->eml_unat &= ~((0x0fUL << IA64_PT_REGS_R8_SLOT)
93 | (1UL << IA64_PT_REGS_R2_SLOT));
94 regs->eml_unat |= (((info->nats >> 8) & 0x0f) << IA64_PT_REGS_R8_SLOT)
95 | (((info->nats >> 2) & 1) << IA64_PT_REGS_R2_SLOT);
97 /* Unmask events. */
98 vcpu->vcpu_info->evtchn_upcall_mask = 0;
100 /* Then apply commands. */
101 if (info->cause & 1) {
102 emulate_io_update (vcpu, info->arg0, info->arg1, info->arg2);
103 }
104 }
106 void
107 sioemu_deliver_event (void)
108 {
109 struct sioemu_callback_info *info;
111 info = sioemu_deliver ();
112 info->cause = SIOEMU_CB_EVENT;
113 }
115 void
116 sioemu_io_emulate (unsigned long padr, unsigned long data,
117 unsigned long data1, unsigned long word)
118 {
119 struct sioemu_callback_info *info;
121 info = sioemu_deliver ();
122 info->cause = SIOEMU_CB_IO_EMULATE;
123 info->arg0 = padr;
124 info->arg1 = data;
125 info->arg2 = data1;
126 info->arg3 = word;
127 }
129 void
130 sioemu_sal_assist (struct vcpu *v)
131 {
132 struct sioemu_callback_info *info;
134 info = sioemu_deliver ();
135 info->cause = SIOEMU_CB_SAL_ASSIST;
136 }
138 static int
139 sioemu_set_callback (struct vcpu *v, unsigned long cb_ip, unsigned long paddr)
140 {
141 struct page_info *page;
142 unsigned long mfn;
143 pte_t pte;
145 v->arch.event_callback_ip = cb_ip;
146 if ((paddr & 0xfff) || v->arch.arch_vmx.sioemu_info_mva)
147 return -EINVAL;
148 pte = *lookup_noalloc_domain_pte(v->domain, paddr);
149 if (!pte_present(pte) || !pte_mem(pte))
150 return -EINVAL;
151 mfn = (pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT;
152 ASSERT(mfn_valid(mfn));
154 page = mfn_to_page(mfn);
155 if (get_page(page, v->domain) == 0)
156 return -EINVAL;
157 v->arch.arch_vmx.sioemu_info_gpa = paddr;
158 v->arch.arch_vmx.sioemu_info_mva = mfn_to_virt(mfn);
159 return 0;
160 }
162 static int
163 sioemu_add_io_physmap (struct domain *d, unsigned long start,
164 unsigned long size, unsigned long type)
165 {
166 unsigned long i;
167 int res;
169 /* Convert to ppn. */
170 type <<= PAGE_SHIFT;
172 /* Check type. */
173 if (type == 0 || (type & _PAGE_PPN_MASK) != type)
174 return -EINVAL;
175 if ((start & (PAGE_SIZE -1)) || (size & (PAGE_SIZE - 1)))
176 return -EINVAL;
178 /* Check area is currently unassigned. */
179 for (i = start; i < start + size; i += PAGE_SIZE) {
180 if (____lookup_domain_mpa(d, i) != INVALID_MFN)
181 return -EBUSY;
182 }
184 /* Set. */
185 for (i = start; i < start + size; i += PAGE_SIZE) {
186 res = __assign_domain_page(d, i, type, ASSIGN_writable | ASSIGN_io);
187 if (res != 0)
188 return res;
189 }
191 return 0;
192 }
194 void
195 sioemu_hypercall (struct pt_regs *regs)
196 {
197 //printk ("sioemu_hypercall: r2=%lx r8=%lx r9=%lx\n",
198 // regs->r2, regs->r8, regs->r9);
200 if (current->vcpu_info->evtchn_upcall_mask == 0)
201 panic_domain(NULL, "sioemu_hypercall: not in stub mode\n");
203 switch (regs->r2 & FW_HYPERCALL_NUM_MASK_LOW)
204 {
205 case SIOEMU_HYPERCALL_SET_CALLBACK:
206 regs->r8 = sioemu_set_callback(current, regs->r8, regs->r9);
207 break;
208 case SIOEMU_HYPERCALL_START_FW:
209 regs->cr_iip = regs->r8;
210 vmx_vcpu_set_psr(current, regs->r9);
211 current->vcpu_info->evtchn_upcall_mask = 0;
212 break;
213 case SIOEMU_HYPERCALL_ADD_IO_PHYSMAP:
214 regs->r8 = sioemu_add_io_physmap(current->domain,
215 regs->r8, regs->r9, regs->r10);
216 break;
217 case SIOEMU_HYPERCALL_GET_TIME:
218 {
219 uint64_t sec, nsec, now;
220 get_wallclock(&sec, &nsec, &now);
221 regs->r8 = (sec << 30) + nsec;
222 regs->r9 = now;
223 break;
224 }
225 case SIOEMU_HYPERCALL_FLUSH_CACHE:
226 regs->r8 = ia64_sal_cache_flush(regs->r8);
227 break;
228 case SIOEMU_HYPERCALL_FREQ_BASE:
229 regs->r8 = ia64_sal_freq_base(regs->r8, &regs->r9, &regs->r10);
230 break;
231 case SIOEMU_HYPERCALL_DELIVER_INT:
232 regs->r8 = vlsapic_deliver_int(current->domain,
233 regs->r8, regs->r9, regs->r10);
234 break;
235 case SIOEMU_HYPERCALL_CALLBACK_RETURN:
236 sioemu_callback_return ();
237 vcpu_decrement_iip(current);
238 break;
239 default:
240 panic_domain (NULL, "bad sioemu hypercall %lx\n", regs->r2);
241 break;
242 }
243 }