vboot: more complete EC sync testing

Add more checks of updated and protected function calls.

Check that VB2_SD_STATUS_EC_SYNC_COMPLETE is always set,
regardless of whether EC sync actually runs.

Only perform action in mock functions when return value
is non-error.

BUG=b:124141368, chromium:1042135
TEST=make clean && make runtests
BRANCH=none

Change-Id: I2e7d9770f4c105d372c6e068a95b4fbc78a085c7
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2004248
Tested-by: Joel Kitching <kitching@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c
index a444930..5123ea7 100644
--- a/tests/vb2_ec_sync_tests.c
+++ b/tests/vb2_ec_sync_tests.c
@@ -18,18 +18,23 @@
 #include "vboot_struct.h"
 
 /* Mock data */
-static int mock_in_rw;
-static vb2_error_t in_rw_retval;
-static int protect_retval;
-static int ec_ro_protected;
-static int ec_rw_protected;
-static int run_retval;
-static int ec_run_image;
-static int update_retval;
 static int ec_ro_updated;
 static int ec_rw_updated;
+static int ec_ro_protected;
+static int ec_rw_protected;
+static int ec_run_image;
+
+static vb2_error_t in_rw_retval;
+static int protect_retval;
+static int jump_retval;
+static int update_retval;
 static int get_expected_retval;
 static int shutdown_request_calls_left;
+static vb2_error_t ec_vboot_done_retval;
+static int ec_vboot_done_calls;
+
+static uint32_t screens_displayed[8];
+static uint32_t screens_count = 0;
 
 static uint8_t mock_ec_ro_hash[32];
 static uint8_t mock_ec_rw_hash[32];
@@ -43,10 +48,6 @@
 static struct vb2_context *ctx;
 static struct vb2_shared_data *sd;
 static struct vb2_gbb_header gbb;
-static vb2_error_t ec_vboot_done_retval;
-
-static uint32_t screens_displayed[8];
-static uint32_t screens_count = 0;
 
 /* Reset mock data (for use before each test) */
 static void ResetMocks(void)
@@ -62,18 +63,20 @@
 
 	memset(&gbb, 0, sizeof(gbb));
 
-	mock_in_rw = 0;
+	ec_ro_updated = 0;
+	ec_rw_updated = 0;
 	ec_ro_protected = 0;
 	ec_rw_protected = 0;
 	ec_run_image = 0;   /* 0 = RO, 1 = RW */
-	ec_ro_updated = 0;
-	ec_rw_updated = 0;
+
 	in_rw_retval = VB2_SUCCESS;
 	protect_retval = VB2_SUCCESS;
 	update_retval = VB2_SUCCESS;
-	run_retval = VB2_SUCCESS;
+	jump_retval = VB2_SUCCESS;
 	get_expected_retval = VB2_SUCCESS;
 	shutdown_request_calls_left = -1;
+	ec_vboot_done_retval = VB2_SUCCESS;
+	ec_vboot_done_calls = 0;
 
 	memset(mock_ec_ro_hash, 0, sizeof(mock_ec_ro_hash));
 	mock_ec_ro_hash[0] = 42;
@@ -89,8 +92,6 @@
 
 	update_hash = 42;
 
-	// TODO: ensure these are actually needed
-
 	memset(screens_displayed, 0, sizeof(screens_displayed));
 	screens_count = 0;
 }
@@ -113,34 +114,39 @@
 
 int vb2ex_ec_trusted(void)
 {
-	return !mock_in_rw;
+	return !ec_run_image;
 }
 
 vb2_error_t vb2ex_ec_running_rw(int *in_rw)
 {
-	*in_rw = mock_in_rw;
+	*in_rw = ec_run_image;
 	return in_rw_retval;
 }
 
 vb2_error_t vb2ex_ec_protect(enum vb2_firmware_selection select)
 {
+	if (protect_retval)
+		return protect_retval;
+
 	if (select == VB_SELECT_FIRMWARE_READONLY)
 		ec_ro_protected = 1;
 	else
 		ec_rw_protected = 1;
-	return protect_retval;
+
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2ex_ec_disable_jump(void)
 {
-	return run_retval;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2ex_ec_jump_to_rw(void)
 {
-	ec_run_image = 1;
-	mock_in_rw = 1;
-	return run_retval;
+	if (jump_retval == VB2_SUCCESS)
+		ec_run_image = 1;
+
+	return jump_retval;
 }
 
 vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
@@ -164,6 +170,9 @@
 
 vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
 {
+	if (update_retval)
+		return update_retval;
+
 	if (select == VB_SELECT_FIRMWARE_READONLY) {
 		ec_ro_updated = 1;
 		mock_ec_ro_hash[0] = update_hash;
@@ -171,7 +180,7 @@
 		ec_rw_updated = 1;
 		mock_ec_rw_hash[0] = update_hash;
 	}
-	return update_retval;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t VbDisplayScreen(struct vb2_context *c, uint32_t screen, int force,
@@ -185,6 +194,7 @@
 
 vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *c)
 {
+	ec_vboot_done_calls++;
 	return ec_vboot_done_retval;
 }
 
@@ -200,77 +210,161 @@
 
 static void VbSoftwareSyncTest(void)
 {
+	/* Check flag toggling */
+	ResetMocks();
+	test_ssync(VB2_SUCCESS, 0, "Normal sync");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
+	TEST_EQ(ec_vboot_done_calls, 1, "ec_vboot_done calls");
+	/* Sync again to check ec_vboot_done */
+	test_ssync(VB2_SUCCESS, 0, "Normal sync");
+	TEST_EQ(ec_vboot_done_calls, 1, "ec_vboot_done calls");
+
+	ResetMocks();
+	sd->flags |= VB2_SD_STATUS_EC_SYNC_COMPLETE;
+	test_ssync(VB2_SUCCESS, 0, "EC sync already complete");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
+	TEST_EQ(ec_vboot_done_calls, 0, "ec_vboot_done calls");
+
+	ResetMocks();
+	ctx->flags &= ~VB2_CONTEXT_EC_SYNC_SUPPORTED;
+	test_ssync(VB2_SUCCESS, 0, "EC sync not supported");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
+	TEST_EQ(ec_vboot_done_calls, 1, "ec_vboot_done calls");
+
+	ResetMocks();
+	gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC;
+	test_ssync(VB2_SUCCESS, 0, "EC sync disabled by GBB");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
+	TEST_EQ(ec_vboot_done_calls, 1, "ec_vboot_done calls");
+
 	/* AP-RO cases */
 	ResetMocks();
 	in_rw_retval = VB2_ERROR_MOCK;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	/* Calculate hashes */
 	ResetMocks();
 	mock_ec_rw_hash_size = 0;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_HASH_FAILED, "Bad EC hash");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash_size = 16;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_HASH_SIZE, "Bad EC hash size");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	want_ec_hash_size = 0;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	want_ec_hash_size = 16;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_HASH_SIZE,
 		   "Hash size mismatch");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	want_ec_hash_size = 4;
 	mock_ec_rw_hash_size = 4;
 	test_ssync(0, 0, "Custom hash size");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	/* Updates required */
 	ResetMocks();
-	mock_in_rw = 1;
+	ec_run_image = 1;
 	mock_ec_rw_hash[0]++;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   0, "Pending update needs reboot");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash[0]++;
 	vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 1);
 	test_ssync(0, 0, "Update rw without reboot");
-	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
-	TEST_EQ(ec_run_image, 1, "  ec run image");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
 	TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
 	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash[0]++;
 	mock_ec_ro_hash[0]++;
 	vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 1);
 	test_ssync(0, 0, "Update rw and ro images without reboot");
-	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
-	TEST_EQ(ec_run_image, 1, "  ec run image");
+	TEST_EQ(ec_ro_updated, 1, "  ec ro updated");
 	TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
 	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 1, "  ec ro updated");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	ResetMocks();
 	vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 1);
 	mock_ec_ro_hash[0]++;
 	vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1);
 	test_ssync(0, 0, "rw update not needed");
+	TEST_EQ(ec_ro_updated, 1, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
 	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
 	TEST_EQ(ec_run_image, 1, "  ec run image");
-	TEST_EQ(ec_rw_updated, 0, "  ec rw not updated");
-	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 1, "  ec ro updated");
 	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 1,
 		"  DISPLAY_REQUEST left untouched");
 
@@ -278,42 +372,55 @@
 	mock_ec_rw_hash[0]++;
 	mock_ec_ro_hash[0]++;
 	test_ssync(0, 0, "ro update not requested");
-	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
-	TEST_EQ(ec_run_image, 1, "  ec run image");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
 	TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
 	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash[0]++;
 	update_hash++;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
-		   VB2_RECOVERY_EC_UPDATE, "updated hash mismatch");
-	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
-	TEST_EQ(ec_run_image, 0, "  ec run image");
+		   VB2_RECOVERY_EC_UPDATE, "Updated hash mismatch");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
 	TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
 	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash[0]++;
 	update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
-		   0, "Reboot after rw update");
-	TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
+		   0, "Reboot for rw update");
 	TEST_EQ(ec_ro_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	mock_ec_rw_hash[0]++;
 	update_retval = VB2_ERROR_MOCK;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_UPDATE, "Update failed");
+	TEST_EQ(ec_ro_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	/* Tests related to slow update wait screen */
 	if (EC_SLOW_UPDATE) {
 		ResetMocks();
 		mock_ec_rw_hash[0]++;
 		test_ssync(0, 0, "Slow update");
+		TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+		TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
+		TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
+		TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+		TEST_EQ(ec_run_image, 1, "  ec run image");
 		TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");
 
 		ResetMocks();
@@ -321,12 +428,22 @@
 		sd->flags &= ~VB2_SD_FLAG_DISPLAY_AVAILABLE;
 		test_ssync(VBERROR_REBOOT_REQUIRED, 0,
 			   "Slow update - reboot for display");
+		TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+		TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+		TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+		TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+		TEST_EQ(ec_run_image, 0, "  ec run image");
 
 		ResetMocks();
 		mock_ec_rw_hash[0]++;
 		vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1);
 		test_ssync(VB2_SUCCESS, 0,
 			   "Slow update with display request");
+		TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+		TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
+		TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
+		TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+		TEST_EQ(ec_run_image, 1, "  ec run image");
 		TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");
 		TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 1,
 			"  DISPLAY_REQUEST left untouched");
@@ -337,6 +454,11 @@
 		test_ssync(VB2_SUCCESS, 0,
 			   "Slow update without display request "
 			   "(no reboot needed)");
+		TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+		TEST_EQ(ec_rw_updated, 1, "  ec rw updated");
+		TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
+		TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+		TEST_EQ(ec_run_image, 1, "  ec run image");
 		TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");
 		TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 0,
 			"  DISPLAY_REQUEST left untouched");
@@ -344,52 +466,80 @@
 
 	/* RW cases, no update */
 	ResetMocks();
-	mock_in_rw = 1;
+	ec_run_image = 1;
 	test_ssync(0, 0, "AP-RW, EC-RW");
+	TEST_EQ(ec_ro_updated, 0, "ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "ec ro protected");
+	TEST_EQ(ec_rw_protected, 1, "ec rw protected");
+	TEST_EQ(ec_run_image, 1, "ec run image");
 
 	ResetMocks();
 	test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW");
-	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
-	TEST_EQ(ec_run_image, 1, "  ec run image");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
 	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
 	TEST_EQ(ec_ro_protected, 1, "  ec ro protected");
-	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
+	TEST_EQ(ec_run_image, 1, "  ec run image");
 
 	ResetMocks();
-	run_retval = VB2_ERROR_MOCK;
+	jump_retval = VB2_ERROR_MOCK;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   VB2_RECOVERY_EC_JUMP_RW, "Jump to RW fail");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
-	run_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+	jump_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
 		   0, "Jump to RW fail because locked");
+	TEST_EQ(ec_ro_updated, 0, "  ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "  ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "  ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");
+	TEST_EQ(ec_run_image, 0, "  ec run image");
 
 	ResetMocks();
 	protect_retval = VB2_ERROR_MOCK;
-	test_ssync(VB2_ERROR_MOCK,
-		   VB2_RECOVERY_EC_PROTECT, "Protect error");
+	test_ssync(VB2_ERROR_MOCK, VB2_RECOVERY_EC_PROTECT, "Protect error");
+	TEST_EQ(ec_ro_updated, 0, "ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "ec rw protected");
+	TEST_EQ(ec_run_image, 1, "ec run image");
 
 	/* No longer check for shutdown requested */
 	ResetMocks();
 	shutdown_request_calls_left = 0;
-	test_ssync(0, 0,
-		   "AP-RW, EC-RO -> EC-RW shutdown requested");
+	test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW shutdown requested");
+	TEST_EQ(ec_ro_updated, 0, "ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "ec ro protected");
+	TEST_EQ(ec_rw_protected, 1, "ec rw protected");
+	TEST_EQ(ec_run_image, 1, "ec run image");
 
 	ResetMocks();
-	mock_in_rw = 1;
+	ec_run_image = 1;
 	shutdown_request_calls_left = 0;
 	test_ssync(0, 0, "AP-RW shutdown requested");
+	TEST_EQ(ec_ro_updated, 0, "ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "ec rw updated");
+	TEST_EQ(ec_ro_protected, 1, "ec ro protected");
+	TEST_EQ(ec_rw_protected, 1, "ec rw protected");
+	TEST_EQ(ec_run_image, 1, "ec run image");
 
 	/* EC sync not allowed in recovery mode */
 	ResetMocks();
 	ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
 	test_ssync(0, 0, "No sync in recovery mode");
-	TEST_EQ(ec_ro_protected, 0, "ec ro not protected");
-	TEST_EQ(ec_rw_protected, 0, "ec rw not protected");
-	TEST_EQ(ec_run_image, 0, "ec in ro");
-	TEST_EQ(ec_ro_updated, 0, "ec ro not updated");
-	TEST_EQ(ec_rw_updated, 0, "ec rw not updated");
+	TEST_EQ(ec_ro_updated, 0, "ec ro updated");
+	TEST_EQ(ec_rw_updated, 0, "ec rw updated");
+	TEST_EQ(ec_ro_protected, 0, "ec ro protected");
+	TEST_EQ(ec_rw_protected, 0, "ec rw protected");
+	TEST_EQ(ec_run_image, 0, "ec run image");
 }
 
 int main(void)
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index a376be0..d57ab06 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -81,6 +81,11 @@
 
 /* Mock functions */
 
+struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
+{
+	return &gbb;
+}
+
 vb2_error_t vb2api_kernel_phase1(struct vb2_context *c)
 {
 	sd->kernel_version_secdata = kernel_version;
@@ -178,22 +183,26 @@
 
 static void VbSlkTest(void)
 {
+	/* Normal boot */
 	ResetMocks();
 	test_slk(0, 0, "Normal");
 	TEST_EQ(kernel_version, 0x10002, "  version");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
 
-	/*
-	 * If ctx->flags doesn't ask for software sync, we won't notice that
-	 * error.
-	 */
-	ResetMocks();
-	test_slk(0, 0, "EC sync not done");
-
-	/* Same if ctx->flags asks for sync, but it's overridden by GBB */
+	/* Check EC sync toggling */
 	ResetMocks();
 	ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
 	gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC;
 	test_slk(0, 0, "EC sync disabled by GBB");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
+
+	ResetMocks();
+	ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
+	test_slk(0, 0, "Normal with EC sync");
+	TEST_NEQ(sd->flags & VB2_SD_STATUS_EC_SYNC_COMPLETE, 0,
+		 "  EC sync complete");
 
 	ResetMocks();
 	new_version = 0x20003;