summaryrefslogtreecommitdiff
path: root/firmware/2lib/2auxfw_sync.c
blob: ec0c83450ca7ce7633232ab8b777e367b13adb8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * Auxiliary firmware sync routines for vboot
 */

#include "2api.h"
#include "2common.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2sysincludes.h"
#include "vboot_api.h"
#include "vboot_display.h"

/**
 * Display the WAIT screen
 */
static void display_wait_screen(struct vb2_context *ctx)
{
	VB2_DEBUG("AUX FW update is slow. Show WAIT screen.\n");
	VbDisplayScreen(ctx, VB_SCREEN_WAIT, 0, NULL);
}

/**
 * Determine if we are allowed to update auxfw
 *
 * @param ctx		Vboot2 context
 * @return boolean (true iff we can update auxfw)
 */
static int auxfw_sync_allowed(struct vb2_context *ctx)
{
	struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);

	/* Reasons not to do sync at all */
	if (gbb->flags & VB2_GBB_FLAG_DISABLE_AUXFW_SOFTWARE_SYNC)
		return 0;
	if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
		return 0;
	return 1;
}

/**
 * Update the specified Aux FW and verify the update succeeded
 *
 * @param ctx		Vboot2 context
 * @return VB2_SUCCESS, or non-zero error code.
 */
static vb2_error_t update_auxfw(struct vb2_context *ctx)
{
	vb2_error_t rv;

	VB2_DEBUG("Updating auxfw\n");

	/*
	 * The underlying platform is expected to know how and where to find the
	 * firmware image for all auxfw devices.
	 */
	rv = vb2ex_auxfw_update();
	if (rv != VB2_SUCCESS) {
		VB2_DEBUG("vb2ex_auxfw_update() returned %d\n", rv);

		/*
		 * The device may need a reboot.  It may need to unprotect the
		 * region before updating, or may need to reboot after updating.
		 * Either way, it's not an error requiring recovery mode.
		 *
		 * If we fail for any other reason, trigger recovery mode.
		 */
		if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
			vb2api_fail(ctx, VB2_RECOVERY_AUX_FW_UPDATE, rv);
	}

	return rv;
}

/**
 * Decides if auxfw sync is allowed to be performed
 *
 * If sync is allowed, invokes the external callback,
 * vb2ex_auxfw_check() to allow the client to decide on the auxfw
 * update severity.
 *
 * @param ctx		Vboot2 context
 * @return VB2_SUCCESS, or non-zero error code.
 */
static vb2_error_t auxfw_sync_check_update(struct vb2_context *ctx,
					   enum vb2_auxfw_update_severity *severity)
{
	if (!auxfw_sync_allowed(ctx)) {
		*severity = VB_AUX_FW_NO_UPDATE;
		return VB2_SUCCESS;
	}

	return vb2ex_auxfw_check(severity);
}

vb2_error_t vb2api_auxfw_sync(struct vb2_context *ctx)
{
	enum vb2_auxfw_update_severity fw_update = VB_AUX_FW_NO_UPDATE;
	vb2_error_t rv;

	/* Check for update severity */
	rv = auxfw_sync_check_update(ctx, &fw_update);
	if (rv)
		return rv;

	/* If AUX FW update is slow display the wait screen */
	if (fw_update == VB_AUX_FW_SLOW_UPDATE) {
		/* Display should be available, but better check again */
		if (vb2api_need_reboot_for_display(ctx))
			return VBERROR_REBOOT_REQUIRED;
		display_wait_screen(ctx);
	}

	if (fw_update > VB_AUX_FW_NO_UPDATE) {
		rv = update_auxfw(ctx);
		if (rv)
			return rv;
		/*
		 * AUX FW Update is applied successfully. Request EC reboot to
		 * RO, so that the chips that had FW update get reset to a
		 * clean state.
		 */
		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
	}

	return vb2ex_auxfw_finalize(ctx);
}