blob: 12a4dc0c8d695ed1fb56b95ac17c0622edb1e497 [file] [log] [blame]
Furquan Shaikh6d448e32016-07-22 08:28:57 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2016 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <assert.h>
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070017#include <bootmode.h>
Furquan Shaikh85aa1352016-07-22 08:56:43 -070018#include <bootstate.h>
Furquan Shaikh6d448e32016-07-22 08:28:57 -070019#include <rules.h>
20#include <string.h>
21#include <vb2_api.h>
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070022#include <vboot/misc.h>
23#include <vboot/vbnv.h>
24#include <vboot/vboot_common.h>
Furquan Shaikh6d448e32016-07-22 08:28:57 -070025
26static int vb2_get_recovery_reason_shared_data(void)
27{
28 /* Shared data does not exist for Ramstage and Post-CAR stage. */
29 if (ENV_RAMSTAGE || ENV_POSTCAR)
30 return 0;
31
32 struct vb2_shared_data *sd = vb2_get_shared_data();
33 assert(sd);
34 return sd->recovery_reason;
35}
36
Furquan Shaikh85aa1352016-07-22 08:56:43 -070037void vb2_save_recovery_reason_vbnv(void)
38{
39 if (!IS_ENABLED(CONFIG_VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT))
40 return;
41
42 int reason = vb2_get_recovery_reason_shared_data();
43 if (!reason)
44 return;
45
46 set_recovery_mode_into_vbnv(reason);
47}
48
49static void vb2_clear_recovery_reason_vbnv(void *unused)
50{
51 if (!IS_ENABLED(CONFIG_VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT))
52 return;
53
54 set_recovery_mode_into_vbnv(0);
55}
56
57/*
58 * Recovery reason stored in VBNV needs to be cleared before the state of VBNV
59 * is backed-up anywhere or jumping to the payload (whichever occurs
60 * first). Currently, vbnv_cmos.c backs up VBNV on POST_DEVICE. Thus, we need to
61 * make sure that the stored recovery reason is cleared off before that
62 * happens.
63 * IMPORTANT: Any reboot occurring after BS_DEV_INIT state will cause loss of
64 * recovery reason on reboot. Until now, we have seen reboots occuring on x86
65 * only in FSP stages which run before BS_DEV_INIT.
66 */
67BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT,
68 vb2_clear_recovery_reason_vbnv, NULL);
69
Furquan Shaikh6d448e32016-07-22 08:28:57 -070070/*
71 * Returns 0 for the stages where we know that cbmem does not come online.
72 * Even if this function returns 1 for romstage, depending upon the point in
73 * bootup, cbmem might not actually be online.
74 */
75static int cbmem_possibly_online(void)
76{
77 if (ENV_BOOTBLOCK)
78 return 0;
79
80 if (ENV_VERSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
81 return 0;
82
83 return 1;
84}
85
86/*
87 * Returns 1 if vboot is being used and currently in a stage which might have
88 * already executed vboot verification.
89 */
90static int vboot_possibly_executed(void)
91{
Furquan Shaikh0325dc62016-07-25 13:02:36 -070092 if (!IS_ENABLED(CONFIG_VBOOT))
93 return 0;
94
Furquan Shaikh6d448e32016-07-22 08:28:57 -070095 if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) {
96 if (ENV_BOOTBLOCK && IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
97 return 0;
98 return 1;
99 }
100
101 if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) {
102 if (ENV_BOOTBLOCK)
103 return 0;
104 return 1;
105 }
106
107 return 0;
108}
109
110/*
111 * vb2_check_recovery_request looks up different components to identify if there
112 * is a recovery request and returns appropriate reason code:
113 * 1. Checks if recovery mode is initiated by EC. If yes, returns
114 * VB2_RECOVERY_RO_MANUAL.
115 * 2. Checks if recovery request is present in VBNV and returns the code read
116 * from it.
117 * 3. Checks recovery request in handoff for stages post-cbmem.
118 * 4. For non-CBMEM stages, check if vboot verification is done and look-up
119 * selected region to identify if vboot_refence library has requested recovery
120 * path. If yes, return the reason code from shared data.
121 * 5. If nothing applies, return 0 indicating no recovery request.
122 */
123int vboot_check_recovery_request(void)
124{
125 int reason = 0;
126
127 /* EC-initiated recovery. */
128 if (get_recovery_mode_switch())
129 return VB2_RECOVERY_RO_MANUAL;
130
131 /* Recovery request in VBNV. */
132 if ((reason = get_recovery_mode_from_vbnv()) != 0)
133 return reason;
134
135 /*
136 * Check recovery flag in vboot_handoff for stages post CBMEM coming
137 * online. Since for some stages there is no way to know if cbmem has
138 * already come online, try looking up handoff anyways. If it fails,
139 * flow will fallback to looking up shared data.
140 */
141 if (cbmem_possibly_online() &&
142 ((reason = vboot_handoff_get_recovery_reason()) != 0))
143 return reason;
144
145 /*
146 * For stages where CBMEM might not be online, identify if vboot
147 * verification is already complete and no slot was selected
148 * i.e. recovery path was requested.
149 */
150 if (vboot_possibly_executed() && vb2_logic_executed() &&
151 !vb2_is_slot_selected())
152 return vb2_get_recovery_reason_shared_data();
153
154 return 0;
155}
Furquan Shaikh0325dc62016-07-25 13:02:36 -0700156
157int vboot_recovery_mode_enabled(void)
158{
159 if (!IS_ENABLED(CONFIG_VBOOT))
160 return 0;
161
162 return !!vboot_check_recovery_request();
163}
164
165int vboot_developer_mode_enabled(void)
166{
167 if (!IS_ENABLED(CONFIG_VBOOT))
168 return 0;
169
170 if (get_developer_mode_switch())
171 return 1;
172
173 if (cbmem_possibly_online() && vboot_handoff_check_developer_flag())
174 return 1;
175
176 return 0;
177}