debuggers.hg

annotate xen/arch/x86/hvm/vlapic.c @ 16674:181483b8e959

hvm: Some cleanups to vlapic emulation.
Some of this was suggested by Dexuan Cui.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 19 11:14:05 2007 +0000 (2007-12-19)
parents 966a6d3b7408
children af33f2054f47
rev   line source
kaf24@8746 1 /*
kaf24@8746 2 * vlapic.c: virtualize LAPIC for HVM vcpus.
kaf24@8746 3 *
kaf24@8746 4 * Copyright (c) 2004, Intel Corporation.
kaf24@12578 5 * Copyright (c) 2006 Keir Fraser, XenSource Inc.
kaf24@8746 6 *
kaf24@8746 7 * This program is free software; you can redistribute it and/or modify it
kaf24@8746 8 * under the terms and conditions of the GNU General Public License,
kaf24@8746 9 * version 2, as published by the Free Software Foundation.
kaf24@8746 10 *
kaf24@8746 11 * This program is distributed in the hope it will be useful, but WITHOUT
kaf24@8746 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kaf24@8746 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kaf24@8746 14 * more details.
kaf24@8746 15 *
kaf24@8746 16 * You should have received a copy of the GNU General Public License along with
kaf24@8746 17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
kaf24@8746 18 * Place - Suite 330, Boston, MA 02111-1307 USA.
kaf24@8746 19 */
kaf24@8746 20
kaf24@8746 21 #include <xen/config.h>
kaf24@8746 22 #include <xen/types.h>
kaf24@8746 23 #include <xen/mm.h>
kaf24@8746 24 #include <xen/xmalloc.h>
tdeegan@11189 25 #include <xen/domain_page.h>
kaf24@8746 26 #include <asm/page.h>
kaf24@8746 27 #include <xen/event.h>
kaf24@8746 28 #include <xen/trace.h>
kaf24@8746 29 #include <asm/hvm/hvm.h>
kaf24@8746 30 #include <asm/hvm/io.h>
kaf24@8746 31 #include <asm/hvm/support.h>
kaf24@8746 32 #include <xen/lib.h>
kaf24@8746 33 #include <xen/sched.h>
kaf24@8746 34 #include <asm/current.h>
kfraser@15229 35 #include <asm/hvm/vmx/vmx.h>
kaf24@8746 36 #include <public/hvm/ioreq.h>
kfraser@10949 37 #include <public/hvm/params.h>
kaf24@8746 38
kfraser@12066 39 #define VLAPIC_VERSION 0x00050014
kfraser@12066 40 #define VLAPIC_LVT_NUM 6
kfraser@12066 41
kfraser@13135 42 /* vlapic's frequence is 100 MHz */
kfraser@13135 43 #define APIC_BUS_CYCLE_NS 10
kaf24@8746 44
kfraser@12066 45 #define LVT_MASK \
kfraser@12066 46 APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
kfraser@12066 47
kfraser@12066 48 #define LINT_MASK \
kfraser@12066 49 LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
kfraser@12066 50 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
kfraser@12066 51
kaf24@8746 52 static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
kaf24@8746 53 {
kfraser@10937 54 /* LVTT */
kfraser@10937 55 LVT_MASK | APIC_LVT_TIMER_PERIODIC,
kfraser@10937 56 /* LVTTHMR */
kfraser@10937 57 LVT_MASK | APIC_MODE_MASK,
kfraser@10937 58 /* LVTPC */
kfraser@10937 59 LVT_MASK | APIC_MODE_MASK,
kfraser@10937 60 /* LVT0-1 */
kfraser@10937 61 LINT_MASK, LINT_MASK,
kfraser@10937 62 /* LVTERR */
kfraser@10937 63 LVT_MASK
kaf24@8746 64 };
kaf24@8746 65
kfraser@12066 66 /* Following could belong in apicdef.h */
kfraser@12066 67 #define APIC_SHORT_MASK 0xc0000
kfraser@12066 68 #define APIC_DEST_NOSHORT 0x0
kfraser@12066 69 #define APIC_DEST_MASK 0x800
kfraser@12066 70
kfraser@12433 71 #define vlapic_lvt_vector(vlapic, lvt_type) \
kfraser@12066 72 (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
kfraser@12066 73
kfraser@12433 74 #define vlapic_lvt_dm(vlapic, lvt_type) \
kfraser@12066 75 (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
kfraser@12066 76
kfraser@12433 77 #define vlapic_lvtt_period(vlapic) \
kfraser@12066 78 (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
kfraser@12066 79
kfraser@12433 80
kfraser@12066 81 /*
kfraser@12066 82 * Generic APIC bitmap vector update & search routines.
kfraser@12066 83 */
kfraser@12066 84
kfraser@12066 85 #define VEC_POS(v) ((v)%32)
kfraser@12066 86 #define REG_POS(v) (((v)/32)* 0x10)
kfraser@12066 87 #define vlapic_test_and_set_vector(vec, bitmap) \
kfraser@12066 88 test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
kfraser@12066 89 #define vlapic_test_and_clear_vector(vec, bitmap) \
kfraser@12066 90 test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
kfraser@12066 91 #define vlapic_set_vector(vec, bitmap) \
kfraser@12066 92 set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
kfraser@12066 93 #define vlapic_clear_vector(vec, bitmap) \
kfraser@12066 94 clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
kfraser@12066 95
Tim@13567 96 static int vlapic_find_highest_vector(void *bitmap)
kaf24@8746 97 {
Tim@13567 98 uint32_t *word = bitmap;
kfraser@12066 99 int word_offset = MAX_VECTOR / 32;
kfraser@12066 100
kfraser@12066 101 /* Work backwards through the bitmap (first 32-bit word in every four). */
Tim@13567 102 while ( (word_offset != 0) && (word[(--word_offset)*4] == 0) )
kfraser@12066 103 continue;
kfraser@12066 104
Tim@13567 105 return (fls(word[word_offset*4]) - 1) + (word_offset * 32);
kfraser@12066 106 }
kfraser@12066 107
kfraser@12066 108
kfraser@12066 109 /*
kfraser@12066 110 * IRR-specific bitmap update & search routines.
kfraser@12066 111 */
kfraser@12066 112
kfraser@12066 113 static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
kfraser@12066 114 {
Tim@13567 115 return vlapic_test_and_set_vector(vector, &vlapic->regs->data[APIC_IRR]);
kfraser@12066 116 }
kfraser@12066 117
kfraser@12066 118 static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
kfraser@12066 119 {
Tim@13567 120 vlapic_clear_vector(vector, &vlapic->regs->data[APIC_IRR]);
kaf24@8746 121 }
kaf24@8746 122
keir@16653 123 static int vlapic_find_highest_irr(struct vlapic *vlapic)
kfraser@10937 124 {
keir@16653 125 return vlapic_find_highest_vector(&vlapic->regs->data[APIC_IRR]);
kfraser@10937 126 }
kfraser@10937 127
kfraser@12066 128 int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
kfraser@12066 129 {
kfraser@12066 130 int ret;
kfraser@12066 131
kfraser@12542 132 ret = !vlapic_test_and_set_irr(vec, vlapic);
kfraser@12066 133 if ( trig )
Tim@13567 134 vlapic_set_vector(vec, &vlapic->regs->data[APIC_TMR]);
kfraser@12066 135
kfraser@12066 136 /* We may need to wake up target vcpu, besides set pending bit here */
kfraser@12066 137 return ret;
kfraser@12066 138 }
kfraser@12066 139
keir@16653 140 static int vlapic_find_highest_isr(struct vlapic *vlapic)
kaf24@8746 141 {
keir@16653 142 return vlapic_find_highest_vector(&vlapic->regs->data[APIC_ISR]);
kaf24@8746 143 }
kaf24@8746 144
kfraser@12083 145 uint32_t vlapic_get_ppr(struct vlapic *vlapic)
kaf24@8746 146 {
kaf24@8746 147 uint32_t tpr, isrv, ppr;
kaf24@8746 148 int isr;
kaf24@8746 149
kfraser@12083 150 tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
kfraser@12083 151 isr = vlapic_find_highest_isr(vlapic);
kfraser@12083 152 isrv = (isr != -1) ? isr : 0;
kfraser@10937 153
kfraser@12083 154 if ( (tpr & 0xf0) >= (isrv & 0xf0) )
kfraser@10937 155 ppr = tpr & 0xff;
kaf24@8746 156 else
kfraser@12083 157 ppr = isrv & 0xf0;
kaf24@8746 158
kaf24@8746 159 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
kfraser@15107 160 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
kaf24@8746 161 vlapic, ppr, isr, isrv);
kaf24@8746 162
kaf24@8746 163 return ppr;
kaf24@8746 164 }
kaf24@8746 165
kfraser@12406 166 int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
kfraser@12406 167 {
kfraser@12406 168 int result = 0;
kfraser@12406 169 uint8_t logical_id;
kfraser@12406 170
kfraser@12406 171 logical_id = GET_APIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
kfraser@12406 172
kfraser@12406 173 switch ( vlapic_get_reg(vlapic, APIC_DFR) )
kfraser@12406 174 {
kfraser@12406 175 case APIC_DFR_FLAT:
kfraser@12406 176 if ( logical_id & mda )
kfraser@12406 177 result = 1;
kfraser@12406 178 break;
kfraser@12406 179 case APIC_DFR_CLUSTER:
kfraser@12406 180 if ( ((logical_id >> 4) == (mda >> 0x4)) && (logical_id & mda & 0xf) )
kfraser@12406 181 result = 1;
kfraser@12406 182 break;
kfraser@12406 183 default:
kfraser@14406 184 gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d: %08x\n",
kfraser@14406 185 vlapic_vcpu(vlapic)->vcpu_id,
kfraser@14406 186 vlapic_get_reg(vlapic, APIC_DFR));
kfraser@12406 187 break;
kfraser@12406 188 }
kfraser@12406 189
kfraser@12406 190 return result;
kfraser@12406 191 }
kfraser@12406 192
kaf24@8746 193 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
kfraser@12406 194 int short_hand, int dest, int dest_mode)
kaf24@8746 195 {
kaf24@8746 196 int result = 0;
kfraser@12314 197 struct vlapic *target = vcpu_vlapic(v);
kaf24@8746 198
kaf24@9198 199 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
kfraser@15107 200 "dest_mode 0x%x, short_hand 0x%x",
kfraser@12406 201 target, source, dest, dest_mode, short_hand);
kaf24@8746 202
kfraser@12066 203 switch ( short_hand )
kfraser@12066 204 {
kfraser@12406 205 case APIC_DEST_NOSHORT:
kfraser@12406 206 if ( dest_mode == 0 )
kaf24@9198 207 {
kfraser@12406 208 /* Physical mode. */
kfraser@12593 209 if ( (dest == 0xFF) || (dest == VLAPIC_ID(target)) )
kfraser@12406 210 result = 1;
kfraser@12406 211 }
kfraser@12406 212 else
kfraser@12406 213 {
kfraser@12406 214 /* Logical mode. */
kfraser@12406 215 result = vlapic_match_logical_addr(target, dest);
kaf24@8746 216 }
kaf24@8746 217 break;
kaf24@8746 218
kfraser@10937 219 case APIC_DEST_SELF:
kaf24@9198 220 if ( target == source )
kaf24@8746 221 result = 1;
kaf24@8746 222 break;
kaf24@8746 223
kfraser@10937 224 case APIC_DEST_ALLINC:
kaf24@8746 225 result = 1;
kaf24@8746 226 break;
kaf24@8746 227
kfraser@10937 228 case APIC_DEST_ALLBUT:
kaf24@9198 229 if ( target != source )
kaf24@8746 230 result = 1;
kaf24@8746 231 break;
kaf24@8746 232
kaf24@8746 233 default:
kfraser@12406 234 gdprintk(XENLOG_WARNING, "Bad dest shorthand value %x\n", short_hand);
kaf24@8746 235 break;
kaf24@8746 236 }
kaf24@8746 237
kaf24@8746 238 return result;
kaf24@8746 239 }
kaf24@8746 240
kfraser@12406 241 /* Add a pending IRQ into lapic. */
kaf24@8746 242 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
kaf24@8746 243 int vector, int level, int trig_mode)
kaf24@8746 244 {
kaf24@9198 245 int result = 0;
kfraser@12314 246 struct vlapic *vlapic = vcpu_vlapic(v);
kaf24@8746 247
kfraser@12376 248 switch ( delivery_mode )
kfraser@12376 249 {
kfraser@10937 250 case APIC_DM_FIXED:
kfraser@10937 251 case APIC_DM_LOWEST:
kaf24@8746 252 /* FIXME add logic for vcpu on reset */
kfraser@12433 253 if ( unlikely(!vlapic_enabled(vlapic)) )
kaf24@9198 254 break;
kaf24@8746 255
kfraser@12065 256 if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
kaf24@9198 257 {
kaf24@10544 258 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
kfraser@15107 259 "level trig mode repeatedly for vector %d", vector);
kaf24@9198 260 break;
kaf24@8746 261 }
kaf24@9198 262
kfraser@11092 263 if ( trig_mode )
kaf24@9198 264 {
kaf24@10544 265 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
kfraser@15107 266 "level trig mode for vector %d", vector);
Tim@13567 267 vlapic_set_vector(vector, &vlapic->regs->data[APIC_TMR]);
kaf24@9198 268 }
kaf24@11892 269
kaf24@11892 270 vcpu_kick(v);
kaf24@10544 271
kaf24@8746 272 result = 1;
kaf24@8746 273 break;
kaf24@8746 274
kfraser@10937 275 case APIC_DM_REMRD:
kfraser@12376 276 gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3\n");
kaf24@8746 277 break;
kaf24@8746 278
kfraser@10937 279 case APIC_DM_SMI:
kfraser@13850 280 gdprintk(XENLOG_WARNING, "Ignoring guest SMI\n");
kfraser@13850 281 break;
kfraser@13850 282
kfraser@10937 283 case APIC_DM_NMI:
kfraser@15863 284 if ( !test_and_set_bool(v->nmi_pending) )
kfraser@15426 285 vcpu_kick(v);
kaf24@8746 286 break;
kaf24@8746 287
kfraser@10937 288 case APIC_DM_INIT:
kfraser@12066 289 /* No work on INIT de-assert for P4-type APIC. */
kfraser@12066 290 if ( trig_mode && !(level & APIC_INT_ASSERT) )
kfraser@12066 291 break;
kfraser@12066 292 /* FIXME How to check the situation after vcpu reset? */
kfraser@14692 293 if ( v->is_initialised )
kfraser@13850 294 hvm_vcpu_reset(v);
kfraser@12066 295 v->arch.hvm_vcpu.init_sipi_sipi_state =
kfraser@12066 296 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
kfraser@12066 297 result = 1;
kaf24@8746 298 break;
kaf24@8746 299
kfraser@10937 300 case APIC_DM_STARTUP:
kaf24@9002 301 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
kfraser@12066 302 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
kaf24@8746 303 break;
kaf24@9002 304
kaf24@9002 305 v->arch.hvm_vcpu.init_sipi_sipi_state =
kfraser@12066 306 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
kaf24@9002 307
kfraser@14692 308 if ( v->is_initialised )
kaf24@9198 309 {
kfraser@12376 310 gdprintk(XENLOG_ERR, "SIPI for initialized vcpu %x\n", v->vcpu_id);
kfraser@12407 311 goto exit_and_crash;
kaf24@8746 312 }
kaf24@9002 313
kaf24@9002 314 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
kaf24@9002 315 result = 0;
kaf24@8746 316 break;
kaf24@8746 317
kaf24@8746 318 default:
kfraser@12376 319 gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode %x\n",
kfraser@12376 320 delivery_mode);
kfraser@12407 321 goto exit_and_crash;
kaf24@8746 322 }
kaf24@8746 323
kaf24@8746 324 return result;
kfraser@12407 325
kfraser@12407 326 exit_and_crash:
kfraser@12407 327 domain_crash(v->domain);
kfraser@12407 328 return 0;
kaf24@8746 329 }
kfraser@11092 330
kfraser@12376 331 /* This function is used by both ioapic and lapic.The bitmap is for vcpu_id. */
kfraser@12376 332 struct vlapic *apic_round_robin(
kfraser@12376 333 struct domain *d, uint8_t vector, uint32_t bitmap)
kaf24@8746 334 {
kaf24@8746 335 int next, old;
kfraser@12376 336 struct vlapic *target = NULL;
kaf24@8746 337
kfraser@12542 338 old = next = d->arch.hvm_domain.irq.round_robin_prev_vcpu;
kaf24@8746 339
kfraser@12376 340 do {
kfraser@11092 341 if ( ++next == MAX_VIRT_CPUS )
kaf24@10544 342 next = 0;
kfraser@12433 343 if ( (d->vcpu[next] == NULL) || !test_bit(next, &bitmap) )
kfraser@11092 344 continue;
kfraser@12433 345 target = vcpu_vlapic(d->vcpu[next]);
kfraser@12433 346 if ( vlapic_enabled(target) )
kfraser@12433 347 break;
kfraser@12433 348 target = NULL;
kaf24@9198 349 } while ( next != old );
kaf24@8746 350
kfraser@12542 351 d->arch.hvm_domain.irq.round_robin_prev_vcpu = next;
kaf24@9198 352
kaf24@8746 353 return target;
kaf24@8746 354 }
kaf24@8746 355
kaf24@9198 356 void vlapic_EOI_set(struct vlapic *vlapic)
kaf24@8746 357 {
kaf24@8746 358 int vector = vlapic_find_highest_isr(vlapic);
kaf24@8746 359
kfraser@12433 360 /* Some EOI writes may not have a matching to an in-service interrupt. */
kaf24@9198 361 if ( vector == -1 )
kfraser@12433 362 return;
kaf24@8746 363
Tim@13567 364 vlapic_clear_vector(vector, &vlapic->regs->data[APIC_ISR]);
kaf24@8746 365
Tim@13567 366 if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
kfraser@12315 367 vioapic_update_EOI(vlapic_domain(vlapic), vector);
kaf24@8746 368 }
kaf24@8746 369
kfraser@10951 370 static void vlapic_ipi(struct vlapic *vlapic)
kaf24@8746 371 {
kfraser@10937 372 uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR);
kfraser@10937 373 uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2);
kfraser@10937 374
kfraser@10937 375 unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
kfraser@10937 376 unsigned int short_hand = icr_low & APIC_SHORT_MASK;
kfraser@11092 377 unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
kfraser@11092 378 unsigned int level = icr_low & APIC_INT_ASSERT;
kfraser@10937 379 unsigned int dest_mode = icr_low & APIC_DEST_MASK;
kfraser@12314 380 unsigned int delivery_mode =icr_low & APIC_MODE_MASK;
kfraser@10937 381 unsigned int vector = icr_low & APIC_VECTOR_MASK;
kaf24@8746 382
kaf24@8746 383 struct vlapic *target;
kfraser@12314 384 struct vcpu *v;
kfraser@12314 385 uint32_t lpr_map = 0;
kaf24@8746 386
kaf24@9198 387 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
kaf24@9198 388 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
kfraser@15107 389 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x",
kfraser@10937 390 icr_high, icr_low, short_hand, dest,
kaf24@9198 391 trig_mode, level, dest_mode, delivery_mode, vector);
kaf24@8746 392
kfraser@12314 393 for_each_vcpu ( vlapic_domain(vlapic), v )
kaf24@9198 394 {
kfraser@12406 395 if ( vlapic_match_dest(v, vlapic, short_hand, dest, dest_mode) )
kaf24@9198 396 {
kfraser@12406 397 if ( delivery_mode == APIC_DM_LOWEST )
keir@16614 398 __set_bit(v->vcpu_id, &lpr_map);
kaf24@9198 399 else
kaf24@8746 400 vlapic_accept_irq(v, delivery_mode,
kaf24@8746 401 vector, level, trig_mode);
kaf24@8746 402 }
kaf24@8746 403 }
kaf24@8746 404
kfraser@12376 405 if ( delivery_mode == APIC_DM_LOWEST )
kaf24@9198 406 {
kfraser@12376 407 target = apic_round_robin(vlapic_domain(v), vector, lpr_map);
kfraser@12314 408 if ( target != NULL )
kfraser@12314 409 vlapic_accept_irq(vlapic_vcpu(target), delivery_mode,
kaf24@8746 410 vector, level, trig_mode);
kaf24@8746 411 }
kaf24@8746 412 }
kaf24@8746 413
kfraser@10937 414 static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
kfraser@10937 415 {
kfraser@13135 416 struct vcpu *v = current;
kfraser@13135 417 uint32_t tmcct, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
kfraser@13135 418 uint64_t counter_passed;
kfraser@10937 419
keir@16574 420 counter_passed = ((hvm_get_guest_time(v) - vlapic->timer_last_update)
keir@16574 421 * 1000000000ULL / ticks_per_sec(v)
keir@16574 422 / APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor);
kfraser@13135 423 tmcct = tmict - counter_passed;
kfraser@10937 424
kfraser@10937 425 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
kfraser@13135 426 "timer initial count %d, timer current count %d, "
kfraser@15107 427 "offset %"PRId64,
kfraser@13135 428 tmict, tmcct, counter_passed);
kfraser@10937 429
kfraser@10937 430 return tmcct;
kfraser@10937 431 }
kfraser@10937 432
kfraser@12375 433 static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
kfraser@12375 434 {
kfraser@12375 435 /* Only bits 0, 1 and 3 are settable; others are MBZ. */
kfraser@12375 436 val &= 0xb;
kfraser@12375 437 vlapic_set_reg(vlapic, APIC_TDCR, val);
kfraser@12375 438
Tim@13567 439 /* Update the demangled hw.timer_divisor. */
kfraser@12375 440 val = ((val & 3) | ((val & 8) >> 1)) + 1;
Tim@13567 441 vlapic->hw.timer_divisor = 1 << (val & 7);
kfraser@13135 442
kfraser@13135 443 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
kfraser@15107 444 "timer_divisor: %d", vlapic->hw.timer_divisor);
kfraser@12375 445 }
kfraser@12375 446
keir@16653 447 static void vlapic_read_aligned(
keir@16653 448 struct vlapic *vlapic, unsigned int offset, unsigned int *result)
kaf24@8746 449 {
kfraser@12376 450 switch ( offset )
kfraser@12376 451 {
kfraser@12065 452 case APIC_PROCPRI:
kfraser@12083 453 *result = vlapic_get_ppr(vlapic);
kfraser@12065 454 break;
kfraser@12065 455
kfraser@12066 456 case APIC_TMCCT: /* Timer CCR */
kfraser@10937 457 *result = vlapic_get_tmcct(vlapic);
kaf24@8746 458 break;
kaf24@8746 459
kaf24@8746 460 default:
kfraser@10937 461 *result = vlapic_get_reg(vlapic, offset);
kaf24@8746 462 break;
kaf24@8746 463 }
kaf24@8746 464 }
kaf24@8746 465
kaf24@8746 466 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
kaf24@8746 467 unsigned long len)
kaf24@8746 468 {
kaf24@8746 469 unsigned int alignment;
kaf24@8746 470 unsigned int tmp;
kaf24@8746 471 unsigned long result;
kfraser@12314 472 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@12433 473 unsigned int offset = address - vlapic_base_address(vlapic);
kaf24@8746 474
keir@16674 475 if ( offset > (APIC_TDCR + 0x3) )
kfraser@10937 476 return 0;
kfraser@10937 477
kaf24@8746 478 alignment = offset & 0x3;
kaf24@8746 479
keir@16653 480 vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
kfraser@12376 481 switch ( len )
kfraser@12376 482 {
kaf24@8746 483 case 1:
kaf24@8746 484 result = *((unsigned char *)&tmp + alignment);
kaf24@8746 485 break;
kaf24@8746 486
kaf24@8746 487 case 2:
keir@16653 488 if ( alignment == 3 )
keir@16653 489 goto unaligned_exit_and_crash;
kaf24@8746 490 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
kaf24@8746 491 break;
kaf24@8746 492
kaf24@8746 493 case 4:
keir@16653 494 if ( alignment != 0 )
keir@16653 495 goto unaligned_exit_and_crash;
kaf24@8746 496 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
kaf24@8746 497 break;
kaf24@8746 498
kaf24@8746 499 default:
kfraser@12376 500 gdprintk(XENLOG_ERR, "Local APIC read with len=0x%lx, "
kfraser@12376 501 "should be 4 instead.\n", len);
kfraser@12407 502 goto exit_and_crash;
kaf24@8746 503 }
kaf24@8746 504
kaf24@9198 505 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
kfraser@15107 506 "and the result is 0x%lx", offset, len, result);
kaf24@9198 507
kaf24@8746 508 return result;
kfraser@12407 509
keir@16653 510 unaligned_exit_and_crash:
keir@16653 511 gdprintk(XENLOG_ERR, "Unaligned LAPIC read len=0x%lx at offset=0x%x.\n",
keir@16653 512 len, offset);
kfraser@12407 513 exit_and_crash:
kfraser@12407 514 domain_crash(v->domain);
kfraser@12407 515 return 0;
kaf24@8746 516 }
kaf24@8746 517
keir@16275 518 void vlapic_pt_cb(struct vcpu *v, void *data)
keir@16275 519 {
keir@16275 520 *(s_time_t *)data = hvm_get_guest_time(v);
keir@16275 521 }
keir@16275 522
kaf24@8746 523 static void vlapic_write(struct vcpu *v, unsigned long address,
kaf24@8746 524 unsigned long len, unsigned long val)
kaf24@8746 525 {
kfraser@12314 526 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@12433 527 unsigned int offset = address - vlapic_base_address(vlapic);
kaf24@8746 528
kaf24@9198 529 if ( offset != 0xb0 )
kaf24@8746 530 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
kfraser@15107 531 "offset 0x%x with length 0x%lx, and value is 0x%lx",
kaf24@9198 532 offset, len, val);
kaf24@8746 533
kaf24@8746 534 /*
kfraser@12066 535 * According to the IA32 Manual, all accesses should be 32 bits.
kfraser@12066 536 * Some OSes do 8- or 16-byte accesses, however.
kaf24@8746 537 */
keir@16674 538 val = (uint32_t)val;
kaf24@9198 539 if ( len != 4 )
kaf24@9198 540 {
kaf24@8746 541 unsigned int tmp;
kaf24@8746 542 unsigned char alignment;
kaf24@8746 543
kfraser@12066 544 gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
kfraser@12066 545
kaf24@8746 546 alignment = offset & 0x3;
kaf24@9198 547 tmp = vlapic_read(v, offset & ~0x3, 4);
kfraser@12066 548
kfraser@12066 549 switch ( len )
kfraser@12066 550 {
kaf24@8746 551 case 1:
keir@16674 552 val = ((tmp & ~(0xff << (8*alignment))) |
keir@16674 553 ((val & 0xff) << (8*alignment)));
kaf24@8746 554 break;
kaf24@8746 555
kaf24@8746 556 case 2:
kfraser@12066 557 if ( alignment & 1 )
keir@16674 558 goto unaligned_exit_and_crash;
keir@16674 559 val = ((tmp & ~(0xffff << (8*alignment))) |
keir@16674 560 ((val & 0xffff) << (8*alignment)));
kaf24@8746 561 break;
kaf24@8746 562
kaf24@8746 563 default:
kfraser@12066 564 gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
kfraser@12066 565 "should be 4 instead\n", len);
keir@16674 566 goto exit_and_crash;
kaf24@8746 567 }
kaf24@8746 568 }
keir@16674 569 else if ( (offset & 0x3) != 0 )
keir@16674 570 goto unaligned_exit_and_crash;
kaf24@8746 571
keir@16674 572 offset &= ~0x3;
kaf24@8746 573
kfraser@12066 574 switch ( offset )
kfraser@12066 575 {
kaf24@8746 576 case APIC_TASKPRI:
kfraser@10937 577 vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
kaf24@8746 578 break;
kaf24@8746 579
kaf24@8746 580 case APIC_EOI:
kaf24@8746 581 vlapic_EOI_set(vlapic);
kaf24@8746 582 break;
kaf24@8746 583
kaf24@8746 584 case APIC_LDR:
kfraser@10937 585 vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
kaf24@8746 586 break;
kaf24@8746 587
kaf24@8746 588 case APIC_DFR:
kfraser@11092 589 vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
kaf24@8746 590 break;
kaf24@8746 591
kaf24@8746 592 case APIC_SPIV:
kfraser@11092 593 vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
kfraser@10937 594
kfraser@12066 595 if ( !(val & APIC_SPIV_APIC_ENABLED) )
kaf24@9198 596 {
kaf24@9198 597 int i;
kfraser@10937 598 uint32_t lvt_val;
kfraser@10937 599
Tim@13567 600 vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
kfraser@10937 601
kaf24@9198 602 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
kfraser@10937 603 {
kfraser@11092 604 lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
kfraser@10937 605 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
kfraser@10937 606 lvt_val | APIC_LVT_MASKED);
kfraser@10937 607 }
kaf24@8746 608 }
kaf24@8746 609 else
Tim@13567 610 vlapic->hw.disabled &= ~VLAPIC_SW_DISABLED;
kaf24@8746 611 break;
kaf24@8746 612
kaf24@8746 613 case APIC_ESR:
kfraser@12066 614 /* Nothing to do. */
kaf24@8746 615 break;
kaf24@8746 616
kaf24@8746 617 case APIC_ICR:
kaf24@8746 618 /* No delay here, so we always clear the pending bit*/
kfraser@10937 619 vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12));
kaf24@8746 620 vlapic_ipi(vlapic);
kaf24@8746 621 break;
kaf24@8746 622
kaf24@8746 623 case APIC_ICR2:
kfraser@10937 624 vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
kaf24@8746 625 break;
kaf24@8746 626
kfraser@12066 627 case APIC_LVTT: /* LVT Timer Reg */
kfraser@13135 628 vlapic->pt.irq = val & APIC_VECTOR_MASK;
kfraser@12066 629 case APIC_LVTTHMR: /* LVT Thermal Monitor */
kfraser@12066 630 case APIC_LVTPC: /* LVT Performance Counter */
kfraser@12066 631 case APIC_LVT0: /* LVT LINT0 Reg */
kfraser@12066 632 case APIC_LVT1: /* LVT Lint1 Reg */
kfraser@12066 633 case APIC_LVTERR: /* LVT Error Reg */
kfraser@12433 634 if ( vlapic_sw_disabled(vlapic) )
kfraser@12066 635 val |= APIC_LVT_MASKED;
kfraser@12066 636 val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
kfraser@12066 637 vlapic_set_reg(vlapic, offset, val);
kfraser@12433 638 break;
kaf24@8746 639
kaf24@8746 640 case APIC_TMICT:
kfraser@12066 641 {
keir@16524 642 uint64_t period = (uint64_t)APIC_BUS_CYCLE_NS *
keir@16524 643 (uint32_t)val * vlapic->hw.timer_divisor;
kaf24@9198 644
kfraser@12066 645 vlapic_set_reg(vlapic, APIC_TMICT, val);
Tim@13453 646 create_periodic_time(current, &vlapic->pt, period, vlapic->pt.irq,
keir@16275 647 !vlapic_lvtt_period(vlapic), vlapic_pt_cb,
keir@16275 648 &vlapic->timer_last_update);
keir@16574 649 vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
kaf24@8746 650
kfraser@12066 651 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
kfraser@13135 652 "bus cycle is %uns, "
kfraser@13135 653 "initial count %lu, period %"PRIu64"ns",
kfraser@13135 654 APIC_BUS_CYCLE_NS, val, period);
kfraser@12066 655 }
kfraser@12066 656 break;
kaf24@8746 657
kaf24@8746 658 case APIC_TDCR:
kfraser@12375 659 vlapic_set_tdcr(vlapic, val & 0xb);
kfraser@12375 660 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
Tim@13567 661 vlapic->hw.timer_divisor);
kfraser@12375 662 break;
kaf24@8746 663
kaf24@8746 664 default:
kfraser@12711 665 gdprintk(XENLOG_DEBUG,
kfraser@12273 666 "Local APIC Write to read-only register 0x%x\n", offset);
kaf24@8746 667 break;
kaf24@8746 668 }
keir@16674 669
keir@16674 670 return;
keir@16674 671
keir@16674 672 unaligned_exit_and_crash:
keir@16674 673 gdprintk(XENLOG_ERR, "Unaligned LAPIC write len=0x%lx at offset=0x%x.\n",
keir@16674 674 len, offset);
keir@16674 675 exit_and_crash:
keir@16674 676 domain_crash(v->domain);
kaf24@8746 677 }
kaf24@8746 678
kaf24@8746 679 static int vlapic_range(struct vcpu *v, unsigned long addr)
kaf24@8746 680 {
kfraser@12314 681 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@12433 682 unsigned long offset = addr - vlapic_base_address(vlapic);
kfraser@12433 683 return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
kaf24@8746 684 }
kaf24@8746 685
kaf24@8746 686 struct hvm_mmio_handler vlapic_mmio_handler = {
kaf24@8746 687 .check_handler = vlapic_range,
kaf24@8746 688 .read_handler = vlapic_read,
kaf24@8746 689 .write_handler = vlapic_write
kaf24@8746 690 };
kaf24@8746 691
kaf24@8746 692 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
kaf24@8746 693 {
Tim@13567 694 if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
kfraser@12433 695 {
kfraser@12433 696 if ( value & MSR_IA32_APICBASE_ENABLE )
kfraser@12433 697 {
kfraser@12433 698 vlapic_reset(vlapic);
Tim@13567 699 vlapic->hw.disabled &= ~VLAPIC_HW_DISABLED;
kfraser@12433 700 }
kfraser@12433 701 else
kfraser@12433 702 {
Tim@13567 703 vlapic->hw.disabled |= VLAPIC_HW_DISABLED;
kfraser@12433 704 }
kfraser@12433 705 }
kaf24@8746 706
Tim@13567 707 vlapic->hw.apic_base_msr = value;
kaf24@8746 708
kfraser@15229 709 vmx_vlapic_msr_changed(vlapic_vcpu(vlapic));
kfraser@15229 710
kaf24@8746 711 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
kfraser@15107 712 "apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr);
kaf24@8746 713 }
kaf24@8746 714
kaf24@9198 715 int vlapic_accept_pic_intr(struct vcpu *v)
kaf24@8746 716 {
kfraser@12314 717 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@12433 718 uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
kaf24@8746 719
kfraser@12433 720 /*
kfraser@12433 721 * Only CPU0 is wired to the 8259A. INTA cycles occur if LINT0 is set up
kfraser@12433 722 * accept ExtInts, or if the LAPIC is disabled (so LINT0 behaves as INTR).
kfraser@12433 723 */
kfraser@12433 724 return ((v->vcpu_id == 0) &&
kfraser@12433 725 (((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
kfraser@12433 726 vlapic_hw_disabled(vlapic)));
kaf24@8746 727 }
kaf24@8746 728
keir@16022 729 int vlapic_has_pending_irq(struct vcpu *v)
kaf24@8746 730 {
kfraser@12314 731 struct vlapic *vlapic = vcpu_vlapic(v);
keir@16022 732 int irr, isr;
kaf24@8746 733
kfraser@12433 734 if ( !vlapic_enabled(vlapic) )
kfraser@12066 735 return -1;
kaf24@8746 736
keir@16022 737 irr = vlapic_find_highest_irr(vlapic);
keir@16022 738 if ( irr == -1 )
kfraser@12066 739 return -1;
kaf24@8746 740
keir@16022 741 isr = vlapic_find_highest_isr(vlapic);
keir@16022 742 isr = (isr != -1) ? isr : 0;
keir@16022 743 if ( (isr & 0xf0) >= (irr & 0xf0) )
keir@16022 744 return -1;
keir@16022 745
keir@16022 746 return irr;
kaf24@9233 747 }
kaf24@10544 748
keir@16022 749 int vlapic_ack_pending_irq(struct vcpu *v, int vector)
kaf24@9198 750 {
kfraser@12314 751 struct vlapic *vlapic = vcpu_vlapic(v);
kaf24@8746 752
Tim@13567 753 vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]);
kfraser@13135 754 vlapic_clear_irr(vector, vlapic);
keir@16022 755
keir@16022 756 return 1;
kaf24@8746 757 }
kaf24@8746 758
kfraser@12433 759 /* Reset the VLPAIC back to its power-on/reset state. */
kfraser@13850 760 void vlapic_reset(struct vlapic *vlapic)
kaf24@8746 761 {
kfraser@12314 762 struct vcpu *v = vlapic_vcpu(vlapic);
kfraser@10937 763 int i;
kaf24@8746 764
kaf24@13237 765 vlapic_set_reg(vlapic, APIC_ID, (v->vcpu_id * 2) << 24);
kfraser@12433 766 vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
kfraser@10937 767
kfraser@12433 768 for ( i = 0; i < 8; i++ )
kfraser@12433 769 {
kfraser@12433 770 vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
kfraser@12433 771 vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
kfraser@12433 772 vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
kfraser@12433 773 }
kfraser@12433 774 vlapic_set_reg(vlapic, APIC_ICR, 0);
kfraser@12433 775 vlapic_set_reg(vlapic, APIC_ICR2, 0);
kfraser@12433 776 vlapic_set_reg(vlapic, APIC_LDR, 0);
kfraser@12433 777 vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
kfraser@12433 778 vlapic_set_reg(vlapic, APIC_TMICT, 0);
kfraser@12433 779 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
kfraser@12433 780 vlapic_set_tdcr(vlapic, 0);
kfraser@12433 781
kfraser@12433 782 vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
kfraser@10937 783
kfraser@10937 784 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
kfraser@10937 785 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
kaf24@8746 786
kfraser@10937 787 vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
Tim@13567 788 vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
kaf24@8746 789 }
kaf24@8746 790
Tim@13453 791 #ifdef HVM_DEBUG_SUSPEND
Tim@13453 792 static void lapic_info(struct vlapic *s)
Tim@13453 793 {
Tim@13453 794 printk("*****lapic state:*****\n");
Tim@13567 795 printk("lapic 0x%"PRIx64".\n", s->hw.apic_base_msr);
Tim@13567 796 printk("lapic 0x%x.\n", s->hw.disabled);
Tim@13567 797 printk("lapic 0x%x.\n", s->hw.timer_divisor);
Tim@13453 798 }
Tim@13453 799 #else
Tim@13453 800 static void lapic_info(struct vlapic *s)
Tim@13453 801 {
Tim@13453 802 }
Tim@13453 803 #endif
Tim@13453 804
Tim@13778 805 /* rearm the actimer if needed, after a HVM restore */
Tim@13778 806 static void lapic_rearm(struct vlapic *s)
Tim@13453 807 {
Tim@13453 808 unsigned long tmict;
Tim@13453 809
Tim@13453 810 tmict = vlapic_get_reg(s, APIC_TMICT);
keir@16524 811 if ( tmict > 0 )
keir@16524 812 {
keir@16524 813 uint64_t period = (uint64_t)APIC_BUS_CYCLE_NS *
keir@16524 814 (uint32_t)tmict * s->hw.timer_divisor;
edwin@13745 815 uint32_t lvtt = vlapic_get_reg(s, APIC_LVTT);
Tim@13453 816
edwin@13745 817 s->pt.irq = lvtt & APIC_VECTOR_MASK;
Tim@13778 818 create_periodic_time(vlapic_vcpu(s), &s->pt, period, s->pt.irq,
keir@16275 819 !vlapic_lvtt_period(s), vlapic_pt_cb,
keir@16275 820 &s->timer_last_update);
keir@16574 821 s->timer_last_update = s->pt.last_plt_gtime;
Tim@13453 822
Tim@13453 823 printk("lapic_load to rearm the actimer:"
keir@16524 824 "bus cycle is %uns, "
keir@16524 825 "saved tmict count %lu, period %"PRIu64"ns, irq=%"PRIu8"\n",
keir@16524 826 APIC_BUS_CYCLE_NS, tmict, period, s->pt.irq);
Tim@13453 827 }
Tim@13453 828
Tim@13778 829 lapic_info(s);
Tim@13778 830 }
Tim@13778 831
Tim@13778 832 static int lapic_save_hidden(struct domain *d, hvm_domain_context_t *h)
Tim@13778 833 {
Tim@13778 834 struct vcpu *v;
Tim@13778 835 struct vlapic *s;
Tim@13778 836
Tim@13778 837 for_each_vcpu(d, v)
Tim@13778 838 {
Tim@13778 839 s = vcpu_vlapic(v);
Tim@13778 840 lapic_info(s);
Tim@13778 841
Tim@13778 842 if ( hvm_save_entry(LAPIC, v->vcpu_id, h, &s->hw) != 0 )
Tim@13778 843 return 1;
Tim@13778 844 }
Tim@13778 845 return 0;
Tim@13778 846 }
Tim@13778 847
Tim@13778 848 static int lapic_save_regs(struct domain *d, hvm_domain_context_t *h)
Tim@13778 849 {
Tim@13778 850 struct vcpu *v;
Tim@13778 851 struct vlapic *s;
Tim@13778 852
Tim@13778 853 for_each_vcpu(d, v)
Tim@13778 854 {
Tim@13778 855 s = vcpu_vlapic(v);
Tim@13778 856 if ( hvm_save_entry(LAPIC_REGS, v->vcpu_id, h, s->regs) != 0 )
Tim@13778 857 return 1;
Tim@13778 858 }
Tim@13778 859 return 0;
Tim@13778 860 }
Tim@13778 861
Tim@13778 862 static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h)
Tim@13778 863 {
Tim@13778 864 uint16_t vcpuid;
Tim@13778 865 struct vcpu *v;
Tim@13778 866 struct vlapic *s;
Tim@13778 867
Tim@13778 868 /* Which vlapic to load? */
Tim@13778 869 vcpuid = hvm_load_instance(h);
Tim@13778 870 if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL )
Tim@13778 871 {
Tim@13778 872 gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
Tim@13778 873 return -EINVAL;
Tim@13778 874 }
Tim@13778 875 s = vcpu_vlapic(v);
Tim@13778 876
Tim@13778 877 if ( hvm_load_entry(LAPIC, h, &s->hw) != 0 )
Tim@13778 878 return -EINVAL;
Tim@13453 879
Tim@13453 880 lapic_info(s);
kfraser@15229 881
kfraser@15229 882 vmx_vlapic_msr_changed(v);
kfraser@15229 883
Tim@13453 884 return 0;
Tim@13453 885 }
Tim@13453 886
Tim@13778 887 static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h)
Tim@13778 888 {
Tim@13778 889 uint16_t vcpuid;
Tim@13778 890 struct vcpu *v;
Tim@13778 891 struct vlapic *s;
Tim@13778 892
Tim@13778 893 /* Which vlapic to load? */
Tim@13778 894 vcpuid = hvm_load_instance(h);
Tim@13778 895 if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL )
Tim@13778 896 {
Tim@13778 897 gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
Tim@13778 898 return -EINVAL;
Tim@13778 899 }
Tim@13778 900 s = vcpu_vlapic(v);
Tim@13778 901
Tim@13778 902 if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 )
Tim@13778 903 return -EINVAL;
Tim@13778 904
Tim@13778 905 lapic_rearm(s);
Tim@13778 906 return 0;
Tim@13778 907 }
Tim@13778 908
Tim@13857 909 HVM_REGISTER_SAVE_RESTORE(LAPIC, lapic_save_hidden, lapic_load_hidden,
Tim@13857 910 1, HVMSR_PER_VCPU);
Tim@13857 911 HVM_REGISTER_SAVE_RESTORE(LAPIC_REGS, lapic_save_regs, lapic_load_regs,
Tim@13857 912 1, HVMSR_PER_VCPU);
Tim@13778 913
kaf24@8746 914 int vlapic_init(struct vcpu *v)
kaf24@8746 915 {
kfraser@12314 916 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@15564 917 unsigned int memflags = 0;
kaf24@8746 918
kfraser@15107 919 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "%d", v->vcpu_id);
kaf24@8746 920
keir@16638 921 vlapic->pt.source = PTSRC_lapic;
keir@16638 922
kfraser@15564 923 #ifdef __i386__
kfraser@15564 924 /* 32-bit VMX may be limited to 32-bit physical addresses. */
kfraser@15564 925 if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
kfraser@15564 926 memflags = MEMF_bits(32);
kfraser@15564 927 #endif
kfraser@15564 928
kfraser@15564 929 vlapic->regs_page = alloc_domheap_pages(NULL, 0, memflags);
kfraser@10937 930 if ( vlapic->regs_page == NULL )
kfraser@10937 931 {
kfraser@15180 932 dprintk(XENLOG_ERR, "alloc vlapic regs error: %d/%d\n",
kfraser@15180 933 v->domain->domain_id, v->vcpu_id);
kfraser@10937 934 return -ENOMEM;
kfraser@10937 935 }
kfraser@10937 936
kfraser@10937 937 vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
jeremy@15176 938 if ( vlapic->regs == NULL )
jeremy@15176 939 {
kfraser@15180 940 dprintk(XENLOG_ERR, "map vlapic regs error: %d/%d\n",
kfraser@15180 941 v->domain->domain_id, v->vcpu_id);
jeremy@15176 942 return -ENOMEM;
jeremy@15176 943 }
jeremy@15176 944
kfraser@15438 945 clear_page(vlapic->regs);
kfraser@10937 946
kfraser@12314 947 vlapic_reset(vlapic);
kfraser@12314 948
kfraser@15180 949 vlapic->hw.apic_base_msr = (MSR_IA32_APICBASE_ENABLE |
kfraser@15180 950 APIC_DEFAULT_PHYS_BASE);
kfraser@12314 951 if ( v->vcpu_id == 0 )
Tim@13567 952 vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP;
kfraser@12314 953
kaf24@8746 954 return 0;
kaf24@8746 955 }
kfraser@12289 956
kfraser@12289 957 void vlapic_destroy(struct vcpu *v)
kfraser@12289 958 {
kfraser@12314 959 struct vlapic *vlapic = vcpu_vlapic(v);
kfraser@12289 960
kfraser@15317 961 destroy_periodic_time(&vlapic->pt);
kfraser@12289 962 unmap_domain_page_global(vlapic->regs);
kfraser@12289 963 free_domheap_page(vlapic->regs_page);
kfraser@12289 964 }