svn commit: r351609 - head/sys/amd64/vmm/io

John Baldwin jhb at FreeBSD.org
Thu Aug 29 18:23:39 UTC 2019


Author: jhb
Date: Thu Aug 29 18:23:38 2019
New Revision: 351609
URL: https://svnweb.freebsd.org/changeset/base/351609

Log:
  Simplify bhyve vlapic ESR logic.
  
  The bhyve virtual local APIC uses an instance-global flag to indicate
  when an error LVT is being delivered to prevent infinite recursion.
  Use a function argument instead to reduce the amount of instance-global
  state.
  
  This was inspired by reviewing the bhyve save/restore work, which
  saves a copy of the instance-global state for each vlapic.
  
  Smart OS bug:	https://smartos.org/bugview/OS-7777
  Submitted by:	Patrick Mooney
  Reviewed by:	markj, rgrimes
  Obtained from:	SmartOS / Joyent
  Differential Revision:	https://reviews.freebsd.org/D20365

Modified:
  head/sys/amd64/vmm/io/vlapic.c
  head/sys/amd64/vmm/io/vlapic.h
  head/sys/amd64/vmm/io/vlapic_priv.h

Modified: head/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.c	Thu Aug 29 17:25:50 2019	(r351608)
+++ head/sys/amd64/vmm/io/vlapic.c	Thu Aug 29 18:23:38 2019	(r351609)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2011 NetApp, Inc.
  * All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -78,6 +79,8 @@ __FBSDID("$FreeBSD$");
  */
 #define VLAPIC_BUS_FREQ		(128 * 1024 * 1024)
 
+static void vlapic_set_error(struct vlapic *, uint32_t, bool);
+
 static __inline uint32_t
 vlapic_get_id(struct vlapic *vlapic)
 {
@@ -275,7 +278,8 @@ vlapic_set_intr_ready(struct vlapic *vlapic, int vecto
 	}
 
 	if (vector < 16) {
-		vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR);
+		vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR,
+		    false);
 		VLAPIC_CTR1(vlapic, "vlapic ignoring interrupt to vector %d",
 		    vector);
 		return (1);
@@ -432,20 +436,22 @@ vlapic_mask_lvts(struct vlapic *vlapic)
 }
 
 static int
-vlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)
+vlapic_fire_lvt(struct vlapic *vlapic, u_int lvt)
 {
-	uint32_t vec, mode;
+	uint32_t mode, reg, vec;
 
-	if (lvt & APIC_LVT_M)
+	reg = atomic_load_acq_32(&vlapic->lvt_last[lvt]);
+
+	if (reg & APIC_LVT_M)
 		return (0);
+	vec = reg & APIC_LVT_VECTOR;
+	mode = reg & APIC_LVT_DM;
 
-	vec = lvt & APIC_LVT_VECTOR;
-	mode = lvt & APIC_LVT_DM;
-
 	switch (mode) {
 	case APIC_LVT_DM_FIXED:
 		if (vec < 16) {
-			vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
+			vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR,
+			    lvt == APIC_LVT_ERROR);
 			return (0);
 		}
 		if (vlapic_set_intr_ready(vlapic, vec, false))
@@ -606,22 +612,22 @@ vlapic_periodic_timer(struct vlapic *vlapic)
 
 static VMM_STAT(VLAPIC_INTR_ERROR, "error interrupts generated by vlapic");
 
-void
-vlapic_set_error(struct vlapic *vlapic, uint32_t mask)
+static void
+vlapic_set_error(struct vlapic *vlapic, uint32_t mask, bool lvt_error)
 {
-	uint32_t lvt;
 
 	vlapic->esr_pending |= mask;
-	if (vlapic->esr_firing)
+
+	/*
+	 * Avoid infinite recursion if the error LVT itself is configured with
+	 * an illegal vector.
+	 */
+	if (lvt_error)
 		return;
-	vlapic->esr_firing = 1;
 
-	// The error LVT always uses the fixed delivery mode.
-	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
-	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
+	if (vlapic_fire_lvt(vlapic, APIC_LVT_ERROR)) {
 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_ERROR, 1);
 	}
-	vlapic->esr_firing = 0;
 }
 
 static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic");
@@ -629,13 +635,10 @@ static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts g
 static void
 vlapic_fire_timer(struct vlapic *vlapic)
 {
-	uint32_t lvt;
 
 	KASSERT(VLAPIC_TIMER_LOCKED(vlapic), ("vlapic_fire_timer not locked"));
-	
-	// The timer LVT always uses the fixed delivery mode.
-	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
-	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
+
+	if (vlapic_fire_lvt(vlapic, APIC_LVT_TIMER)) {
 		VLAPIC_CTR0(vlapic, "vlapic timer fired");
 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1);
 	}
@@ -647,10 +650,8 @@ static VMM_STAT(VLAPIC_INTR_CMC,
 void
 vlapic_fire_cmci(struct vlapic *vlapic)
 {
-	uint32_t lvt;
 
-	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
-	if (vlapic_fire_lvt(vlapic, lvt)) {
+	if (vlapic_fire_lvt(vlapic, APIC_LVT_CMCI)) {
 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_CMC, 1);
 	}
 }
@@ -661,7 +662,6 @@ static VMM_STAT_ARRAY(LVTS_TRIGGERRED, VLAPIC_MAXLVT_I
 int
 vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
 {
-	uint32_t lvt;
 
 	if (vlapic_enabled(vlapic) == false) {
 		/*
@@ -684,35 +684,20 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
 
 	switch (vector) {
 	case APIC_LVT_LINT0:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT0_LVT);
-		break;
 	case APIC_LVT_LINT1:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT1_LVT);
-		break;
 	case APIC_LVT_TIMER:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
-		lvt |= APIC_LVT_DM_FIXED;
-		break;
 	case APIC_LVT_ERROR:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
-		lvt |= APIC_LVT_DM_FIXED;
-		break;
 	case APIC_LVT_PMC:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_PERF_LVT);
-		break;
 	case APIC_LVT_THERMAL:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_THERM_LVT);
-		break;
 	case APIC_LVT_CMCI:
-		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
+		if (vlapic_fire_lvt(vlapic, vector)) {
+			vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
+			    LVTS_TRIGGERRED, vector, 1);
+		}
 		break;
 	default:
 		return (EINVAL);
 	}
-	if (vlapic_fire_lvt(vlapic, lvt)) {
-		vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
-		    LVTS_TRIGGERRED, vector, 1);
-	}
 	return (0);
 }
 
@@ -980,7 +965,7 @@ vlapic_icrlo_write_handler(struct vlapic *vlapic, bool
 	mode = icrval & APIC_DELMODE_MASK;
 
 	if (mode == APIC_DELMODE_FIXED && vec < 16) {
-		vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
+		vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR, false);
 		VLAPIC_CTR1(vlapic, "Ignoring invalid IPI %d", vec);
 		return (0);
 	}

Modified: head/sys/amd64/vmm/io/vlapic.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.h	Thu Aug 29 17:25:50 2019	(r351608)
+++ head/sys/amd64/vmm/io/vlapic.h	Thu Aug 29 18:23:38 2019	(r351609)
@@ -71,7 +71,6 @@ int vlapic_set_intr_ready(struct vlapic *vlapic, int v
  */
 void vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum);
 
-void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);
 void vlapic_fire_cmci(struct vlapic *vlapic);
 int vlapic_trigger_lvt(struct vlapic *vlapic, int vector);
 

Modified: head/sys/amd64/vmm/io/vlapic_priv.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic_priv.h	Thu Aug 29 17:25:50 2019	(r351608)
+++ head/sys/amd64/vmm/io/vlapic_priv.h	Thu Aug 29 18:23:38 2019	(r351609)
@@ -156,7 +156,6 @@ struct vlapic {
 	struct vlapic_ops	ops;
 
 	uint32_t		esr_pending;
-	int			esr_firing;
 
 	struct callout	callout;	/* vlapic timer */
 	struct bintime	timer_fire_bt;	/* callout expiry time */


More information about the svn-src-head mailing list