debuggers.hg

view xen/arch/x86/hvm/vpic.c @ 19826:2f9e1348aa98

x86_64: allow more vCPU-s per guest

Since the shared info layout is fixed, guests are required to use
VCPUOP_register_vcpu_info prior to booting any vCPU beyond the
traditional limit of 32.

MAX_VIRT_CPUS, being an implemetation detail of the hypervisor, is no
longer being exposed in the public headers.

The tools changes are clearly incomplete (and done only so things
would
build again), and the current state of the tools (using scalar
variables all over the place to represent vCPU bitmaps) very likely
doesn't permit booting DomU-s with more than the traditional number of
vCPU-s. Testing of the extended functionality was done with Dom0 (96
vCPU-s, as well as 128 vCPU-s out of which the kernel elected - by way
of a simple kernel side patch - to use only some, resulting in a
sparse
bitmap).

ia64 changes only to make things build, and build-tested only (and the
tools part only as far as the build would go without encountering
unrelated problems in the blktap code).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 18 10:14:16 2009 +0100 (2009-06-18)
parents e5c696aaf2a6
children 80839a223746
line source
1 /*
2 * i8259 interrupt controller emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2005 Intel Corperation
6 * Copyright (c) 2006 Keir Fraser, XenSource Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
27 #include <xen/config.h>
28 #include <xen/types.h>
29 #include <xen/event.h>
30 #include <xen/lib.h>
31 #include <xen/errno.h>
32 #include <xen/sched.h>
33 #include <asm/hvm/hvm.h>
34 #include <asm/hvm/io.h>
35 #include <asm/hvm/support.h>
37 #define vpic_domain(v) (container_of((v), struct domain, \
38 arch.hvm_domain.vpic[!vpic->is_master]))
39 #define __vpic_lock(v) &container_of((v), struct hvm_domain, \
40 vpic[!(v)->is_master])->irq_lock
41 #define vpic_lock(v) spin_lock(__vpic_lock(v))
42 #define vpic_unlock(v) spin_unlock(__vpic_lock(v))
43 #define vpic_is_locked(v) spin_is_locked(__vpic_lock(v))
44 #define vpic_elcr_mask(v) (vpic->is_master ? (uint8_t)0xf8 : (uint8_t)0xde);
46 /* Return the highest priority found in mask. Return 8 if none. */
47 #define VPIC_PRIO_NONE 8
48 static int vpic_get_priority(struct hvm_hw_vpic *vpic, uint8_t mask)
49 {
50 int prio;
52 ASSERT(vpic_is_locked(vpic));
54 if ( mask == 0 )
55 return VPIC_PRIO_NONE;
57 /* prio = ffs(mask ROR vpic->priority_add); */
58 asm ( "ror %%cl,%b1 ; bsf %1,%0"
59 : "=r" (prio) : "q" ((uint32_t)mask), "c" (vpic->priority_add) );
60 return prio;
61 }
63 /* Return the PIC's highest priority pending interrupt. Return -1 if none. */
64 static int vpic_get_highest_priority_irq(struct hvm_hw_vpic *vpic)
65 {
66 int cur_priority, priority, irq;
67 uint8_t mask;
69 ASSERT(vpic_is_locked(vpic));
71 mask = vpic->irr & ~vpic->imr;
72 priority = vpic_get_priority(vpic, mask);
73 if ( priority == VPIC_PRIO_NONE )
74 return -1;
76 irq = (priority + vpic->priority_add) & 7;
78 /*
79 * Compute current priority. If special fully nested mode on the master,
80 * the IRQ coming from the slave is not taken into account for the
81 * priority computation. In special mask mode, masked interrupts do not
82 * block lower-priority interrupts even if their IS bit is set.
83 */
84 mask = vpic->isr;
85 if ( vpic->special_fully_nested_mode && vpic->is_master && (irq == 2) )
86 mask &= ~(1 << 2);
87 if ( vpic->special_mask_mode )
88 mask &= ~vpic->imr;
89 cur_priority = vpic_get_priority(vpic, mask);
91 /* If a higher priority is found then an irq should be generated. */
92 return (priority < cur_priority) ? irq : -1;
93 }
95 static void vpic_update_int_output(struct hvm_hw_vpic *vpic)
96 {
97 int irq;
99 ASSERT(vpic_is_locked(vpic));
101 irq = vpic_get_highest_priority_irq(vpic);
102 if ( vpic->int_output == (irq >= 0) )
103 return;
105 /* INT line transition L->H or H->L. */
106 vpic->int_output = !vpic->int_output;
108 if ( vpic->int_output )
109 {
110 if ( vpic->is_master )
111 {
112 /* Master INT line is connected to VCPU0's VLAPIC LVT0. */
113 struct vcpu *v = vpic_domain(vpic)->vcpu ?
114 vpic_domain(vpic)->vcpu[0] : NULL;
116 if ( (v != NULL) && vlapic_accept_pic_intr(v) )
117 vcpu_kick(v);
118 }
119 else
120 {
121 /* Assert slave line in master PIC. */
122 (--vpic)->irr |= 1 << 2;
123 vpic_update_int_output(vpic);
124 }
125 }
126 else if ( !vpic->is_master )
127 {
128 /* Clear slave line in master PIC. */
129 (--vpic)->irr &= ~(1 << 2);
130 vpic_update_int_output(vpic);
131 }
132 }
134 static void __vpic_intack(struct hvm_hw_vpic *vpic, int irq)
135 {
136 uint8_t mask = 1 << irq;
138 ASSERT(vpic_is_locked(vpic));
140 /* Edge-triggered: clear the IRR (forget the edge). */
141 if ( !(vpic->elcr & mask) )
142 vpic->irr &= ~mask;
144 if ( !vpic->auto_eoi )
145 vpic->isr |= mask;
146 else if ( vpic->rotate_on_auto_eoi )
147 vpic->priority_add = (irq + 1) & 7;
149 vpic_update_int_output(vpic);
150 }
152 static int vpic_intack(struct hvm_hw_vpic *vpic)
153 {
154 int irq = -1;
156 vpic_lock(vpic);
158 if ( !vpic->int_output )
159 goto out;
161 irq = vpic_get_highest_priority_irq(vpic);
162 BUG_ON(irq < 0);
163 __vpic_intack(vpic, irq);
165 if ( (irq == 2) && vpic->is_master )
166 {
167 vpic++; /* Slave PIC */
168 irq = vpic_get_highest_priority_irq(vpic);
169 BUG_ON(irq < 0);
170 __vpic_intack(vpic, irq);
171 irq += 8;
172 }
174 out:
175 vpic_unlock(vpic);
176 return irq;
177 }
179 static void vpic_ioport_write(
180 struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t val)
181 {
182 int priority, cmd, irq;
183 uint8_t mask;
185 vpic_lock(vpic);
187 if ( (addr & 1) == 0 )
188 {
189 if ( val & 0x10 )
190 {
191 /* ICW1 */
192 /* Clear edge-sensing logic. */
193 vpic->irr &= vpic->elcr;
195 /* No interrupts masked or in service. */
196 vpic->imr = vpic->isr = 0;
198 /* IR7 is lowest priority. */
199 vpic->priority_add = 0;
200 vpic->rotate_on_auto_eoi = 0;
202 vpic->special_mask_mode = 0;
203 vpic->readsel_isr = 0;
204 vpic->poll = 0;
206 if ( !(val & 1) )
207 {
208 /* NO ICW4: ICW4 features are cleared. */
209 vpic->auto_eoi = 0;
210 vpic->special_fully_nested_mode = 0;
211 }
213 vpic->init_state = ((val & 3) << 2) | 1;
214 }
215 else if ( val & 0x08 )
216 {
217 /* OCW3 */
218 if ( val & 0x04 )
219 vpic->poll = 1;
220 if ( val & 0x02 )
221 vpic->readsel_isr = val & 1;
222 if ( val & 0x40 )
223 vpic->special_mask_mode = (val >> 5) & 1;
224 }
225 else
226 {
227 /* OCW2 */
228 cmd = val >> 5;
229 switch ( cmd )
230 {
231 case 0: /* Rotate in AEOI Mode (Clear) */
232 case 4: /* Rotate in AEOI Mode (Set) */
233 vpic->rotate_on_auto_eoi = cmd >> 2;
234 break;
235 case 1: /* Non-Specific EOI */
236 case 5: /* Non-Specific EOI & Rotate */
237 mask = vpic->isr;
238 if ( vpic->special_mask_mode )
239 mask &= ~vpic->imr; /* SMM: ignore masked IRs. */
240 priority = vpic_get_priority(vpic, mask);
241 if ( priority == VPIC_PRIO_NONE )
242 break;
243 irq = (priority + vpic->priority_add) & 7;
244 vpic->isr &= ~(1 << irq);
245 if ( cmd == 5 )
246 vpic->priority_add = (irq + 1) & 7;
247 break;
248 case 3: /* Specific EOI */
249 case 7: /* Specific EOI & Rotate */
250 irq = val & 7;
251 vpic->isr &= ~(1 << irq);
252 if ( cmd == 7 )
253 vpic->priority_add = (irq + 1) & 7;
254 /* Release lock and EOI the physical interrupt (if any). */
255 vpic_update_int_output(vpic);
256 vpic_unlock(vpic);
257 hvm_dpci_eoi(current->domain,
258 hvm_isa_irq_to_gsi((addr >> 7) ? (irq|8) : irq),
259 NULL);
260 return; /* bail immediately */
261 case 6: /* Set Priority */
262 vpic->priority_add = (val + 1) & 7;
263 break;
264 }
265 }
266 }
267 else
268 {
269 switch ( vpic->init_state & 3 )
270 {
271 case 0:
272 /* OCW1 */
273 vpic->imr = val;
274 break;
275 case 1:
276 /* ICW2 */
277 vpic->irq_base = val & 0xf8;
278 vpic->init_state++;
279 if ( !(vpic->init_state & 8) )
280 break; /* CASCADE mode: wait for write to ICW3. */
281 /* SNGL mode: fall through (no ICW3). */
282 case 2:
283 /* ICW3 */
284 vpic->init_state++;
285 if ( !(vpic->init_state & 4) )
286 vpic->init_state = 0; /* No ICW4: init done */
287 break;
288 case 3:
289 /* ICW4 */
290 vpic->special_fully_nested_mode = (val >> 4) & 1;
291 vpic->auto_eoi = (val >> 1) & 1;
292 vpic->init_state = 0;
293 break;
294 }
295 }
297 vpic_update_int_output(vpic);
299 vpic_unlock(vpic);
300 }
302 static uint32_t vpic_ioport_read(struct hvm_hw_vpic *vpic, uint32_t addr)
303 {
304 if ( vpic->poll )
305 {
306 vpic->poll = 0;
307 return vpic_intack(vpic);
308 }
310 if ( (addr & 1) == 0 )
311 return (vpic->readsel_isr ? vpic->isr : vpic->irr);
313 return vpic->imr;
314 }
316 static int vpic_intercept_pic_io(
317 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
318 {
319 struct hvm_hw_vpic *vpic;
321 if ( bytes != 1 )
322 {
323 gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", bytes);
324 return X86EMUL_OKAY;
325 }
327 vpic = &current->domain->arch.hvm_domain.vpic[port >> 7];
329 if ( dir == IOREQ_WRITE )
330 vpic_ioport_write(vpic, port, (uint8_t)*val);
331 else
332 *val = (uint8_t)vpic_ioport_read(vpic, port);
334 return X86EMUL_OKAY;
335 }
337 static int vpic_intercept_elcr_io(
338 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
339 {
340 struct hvm_hw_vpic *vpic;
341 uint32_t data;
343 BUG_ON(bytes != 1);
345 vpic = &current->domain->arch.hvm_domain.vpic[port & 1];
347 if ( dir == IOREQ_WRITE )
348 {
349 /* Some IRs are always edge trig. Slave IR is always level trig. */
350 data = *val & vpic_elcr_mask(vpic);
351 if ( vpic->is_master )
352 data |= 1 << 2;
353 vpic->elcr = data;
354 }
355 else
356 {
357 /* Reader should not see hardcoded level-triggered slave IR. */
358 *val = vpic->elcr & vpic_elcr_mask(vpic);
359 }
361 return X86EMUL_OKAY;
362 }
364 static int vpic_save(struct domain *d, hvm_domain_context_t *h)
365 {
366 struct hvm_hw_vpic *s;
367 int i;
369 /* Save the state of both PICs */
370 for ( i = 0; i < 2 ; i++ )
371 {
372 s = &d->arch.hvm_domain.vpic[i];
373 if ( hvm_save_entry(PIC, i, h, s) )
374 return 1;
375 }
377 return 0;
378 }
380 static int vpic_load(struct domain *d, hvm_domain_context_t *h)
381 {
382 struct hvm_hw_vpic *s;
383 uint16_t inst;
385 /* Which PIC is this? */
386 inst = hvm_load_instance(h);
387 if ( inst > 1 )
388 return -EINVAL;
389 s = &d->arch.hvm_domain.vpic[inst];
391 /* Load the state */
392 if ( hvm_load_entry(PIC, h, s) != 0 )
393 return -EINVAL;
395 return 0;
396 }
398 HVM_REGISTER_SAVE_RESTORE(PIC, vpic_save, vpic_load, 2, HVMSR_PER_DOM);
400 void vpic_reset(struct domain *d)
401 {
402 struct hvm_hw_vpic *vpic;
404 /* Master PIC. */
405 vpic = &d->arch.hvm_domain.vpic[0];
406 memset(vpic, 0, sizeof(*vpic));
407 vpic->is_master = 1;
408 vpic->elcr = 1 << 2;
410 /* Slave PIC. */
411 vpic++;
412 memset(vpic, 0, sizeof(*vpic));
413 }
415 void vpic_init(struct domain *d)
416 {
417 vpic_reset(d);
419 register_portio_handler(d, 0x20, 2, vpic_intercept_pic_io);
420 register_portio_handler(d, 0xa0, 2, vpic_intercept_pic_io);
422 register_portio_handler(d, 0x4d0, 1, vpic_intercept_elcr_io);
423 register_portio_handler(d, 0x4d1, 1, vpic_intercept_elcr_io);
424 }
426 void vpic_irq_positive_edge(struct domain *d, int irq)
427 {
428 struct hvm_hw_vpic *vpic = &d->arch.hvm_domain.vpic[irq >> 3];
429 uint8_t mask = 1 << (irq & 7);
431 ASSERT(irq <= 15);
432 ASSERT(vpic_is_locked(vpic));
434 if ( irq == 2 )
435 return;
437 vpic->irr |= mask;
438 if ( !(vpic->imr & mask) )
439 vpic_update_int_output(vpic);
440 }
442 void vpic_irq_negative_edge(struct domain *d, int irq)
443 {
444 struct hvm_hw_vpic *vpic = &d->arch.hvm_domain.vpic[irq >> 3];
445 uint8_t mask = 1 << (irq & 7);
447 ASSERT(irq <= 15);
448 ASSERT(vpic_is_locked(vpic));
450 if ( irq == 2 )
451 return;
453 vpic->irr &= ~mask;
454 if ( !(vpic->imr & mask) )
455 vpic_update_int_output(vpic);
456 }
458 int vpic_ack_pending_irq(struct vcpu *v)
459 {
460 int irq, vector;
461 struct hvm_hw_vpic *vpic = &v->domain->arch.hvm_domain.vpic[0];
463 if ( !vlapic_accept_pic_intr(v) || !vpic->int_output )
464 return -1;
466 irq = vpic_intack(vpic);
467 if ( irq == -1 )
468 return -1;
470 vector = vpic[irq >> 3].irq_base + (irq & 7);
471 return vector;
472 }