vboot: Change VbExEc implementations to support RO update
[vboot.git] / tests / vboot_api_kernel3_tests.c
1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Tests for vboot_api_kernel, part 3 - software sync
6  */
7
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 #include "gbb_header.h"
13 #include "host_common.h"
14 #include "load_kernel_fw.h"
15 #include "rollback_index.h"
16 #include "test_common.h"
17 #include "vboot_audio.h"
18 #include "vboot_common.h"
19 #include "vboot_kernel.h"
20 #include "vboot_nvstorage.h"
21 #include "vboot_struct.h"
22
23 /* Mock data */
24 static VbCommonParams cparams;
25 static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
26 static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
27 static GoogleBinaryBlockHeader gbb;
28
29 static int trust_ec;
30 static int mock_in_rw;
31 static VbError_t in_rw_retval;
32 static int protect_retval;
33 static int ec_protected;
34 static int run_retval;
35 static int ec_run_image;
36 static int update_retval;
37 static int ec_updated;
38 static int get_expected_retval;
39 static int shutdown_request_calls_left;
40
41 static uint8_t mock_ec_hash[32];
42 static int mock_ec_hash_size;
43 static uint8_t want_ec_hash[32];
44 static int want_ec_hash_size;
45 static uint8_t mock_sha[32];
46
47 static uint32_t screens_displayed[8];
48 static uint32_t screens_count = 0;
49
50 /* Reset mock data (for use before each test) */
51 static void ResetMocks(void)
52 {
53         Memset(&cparams, 0, sizeof(cparams));
54         cparams.shared_data_size = sizeof(shared_data);
55         cparams.shared_data_blob = shared_data;
56         cparams.gbb_data = &gbb;
57
58         Memset(&gbb, 0, sizeof(gbb));
59         gbb.major_version = GBB_MAJOR_VER;
60         gbb.minor_version = GBB_MINOR_VER;
61         gbb.flags = 0;
62
63         /*
64          * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
65          * vnc.  So clear it here too.
66          */
67         Memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
68         VbNvSetup(VbApiKernelGetVnc());
69         VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
70
71         Memset(&shared_data, 0, sizeof(shared_data));
72         VbSharedDataInit(shared, sizeof(shared_data));
73
74         trust_ec = 0;
75         mock_in_rw = 0;
76         ec_protected = 0;
77         ec_run_image = 0;   /* 0 = RO, 1 = RW */
78         ec_updated = 0;
79         in_rw_retval = VBERROR_SUCCESS;
80         protect_retval = VBERROR_SUCCESS;
81         update_retval = VBERROR_SUCCESS;
82         run_retval = VBERROR_SUCCESS;
83         get_expected_retval = VBERROR_SUCCESS;
84         shutdown_request_calls_left = -1;
85
86         Memset(mock_ec_hash, 0, sizeof(mock_ec_hash));
87         mock_ec_hash[0] = 42;
88         mock_ec_hash_size = sizeof(mock_ec_hash);
89
90         Memset(want_ec_hash, 0, sizeof(want_ec_hash));
91         want_ec_hash[0] = 42;
92         want_ec_hash_size = sizeof(want_ec_hash);
93
94         Memset(mock_sha, 0, sizeof(want_ec_hash));
95         mock_sha[0] = 42;
96
97         // TODO: ensure these are actually needed
98
99         Memset(screens_displayed, 0, sizeof(screens_displayed));
100         screens_count = 0;
101 }
102
103 /* Mock functions */
104
105 uint32_t VbExIsShutdownRequested(void)
106 {
107         if (shutdown_request_calls_left == 0)
108                 return 1;
109         else if (shutdown_request_calls_left > 0)
110                 shutdown_request_calls_left--;
111
112         return 0;
113 }
114
115 int VbExTrustEC(int devidx)
116 {
117         return trust_ec;
118 }
119
120 VbError_t VbExEcRunningRW(int devidx, int *in_rw)
121 {
122         *in_rw = mock_in_rw;
123         return in_rw_retval;
124 }
125
126 VbError_t VbExEcProtect(int devidx, enum VbSelectFirmware_t select)
127 {
128         ec_protected = 1;
129         return protect_retval;
130 }
131
132 VbError_t VbExEcDisableJump(int devidx)
133 {
134         return run_retval;
135 }
136
137 VbError_t VbExEcJumpToRW(int devidx)
138 {
139         ec_run_image = 1;
140         return run_retval;
141 }
142
143 VbError_t VbExEcHashImage(int devidx, enum VbSelectFirmware_t select,
144                           const uint8_t **hash, int *hash_size)
145 {
146         *hash = mock_ec_hash;
147         *hash_size = mock_ec_hash_size;
148         return mock_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
149 }
150
151 VbError_t VbExEcGetExpectedImage(int devidx, enum VbSelectFirmware_t select,
152                                  const uint8_t **image, int *image_size)
153 {
154         static uint8_t fake_image[64] = {5, 6, 7, 8};
155         *image = fake_image;
156         *image_size = sizeof(fake_image);
157         return get_expected_retval;
158 }
159
160 VbError_t VbExEcGetExpectedImageHash(int devidx, enum VbSelectFirmware_t select,
161                                      const uint8_t **hash, int *hash_size)
162 {
163         *hash = want_ec_hash;
164         *hash_size = want_ec_hash_size;
165
166         if (want_ec_hash_size == -1)
167                 return VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE;
168         else
169                 return want_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
170 }
171
172 uint8_t *internal_SHA256(const uint8_t *data, uint64_t len, uint8_t *digest)
173 {
174         Memcpy(digest, mock_sha, sizeof(mock_sha));
175         return digest;
176 }
177
178 VbError_t VbExEcUpdateImage(int devidx, enum VbSelectFirmware_t select,
179                             const uint8_t *image, int image_size)
180 {
181         ec_updated = 1;
182         return update_retval;
183 }
184
185 VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
186                           VbNvContext *vncptr)
187 {
188         if (screens_count < ARRAY_SIZE(screens_displayed))
189                 screens_displayed[screens_count++] = screen;
190
191         return VBERROR_SUCCESS;
192 }
193
194 static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
195 {
196         uint32_t u;
197
198         TEST_EQ(VbEcSoftwareSync(0, &cparams), retval, desc);
199         VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
200         TEST_EQ(u, recovery_reason, "  recovery reason");
201 }
202
203 /* Tests */
204
205 static void VbSoftwareSyncTest(void)
206 {
207         /* Recovery cases */
208         ResetMocks();
209         shared->recovery_reason = 123;
210         test_ssync(0, 0, "In recovery, EC-RO");
211         TEST_EQ(ec_protected, 0, "  ec protected");
212
213         ResetMocks();
214         shared->recovery_reason = 123;
215         mock_in_rw = 1;
216         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
217                    123, "Recovery needs EC-RO");
218
219         /* AP-RO cases */
220         ResetMocks();
221         in_rw_retval = VBERROR_SIMULATED;
222         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
223                    VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
224
225         ResetMocks();
226         shared->flags |= VBSD_LF_USE_RO_NORMAL;
227         mock_in_rw = 1;
228         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
229                    0, "AP-RO needs EC-RO");
230
231         ResetMocks();
232         shared->flags |= VBSD_LF_USE_RO_NORMAL;
233         test_ssync(0, 0, "AP-RO, EC-RO");
234         TEST_EQ(ec_protected, 1, "  ec protected");
235         TEST_EQ(ec_run_image, 0, "  ec run image");
236
237         ResetMocks();
238         shared->flags |= VBSD_LF_USE_RO_NORMAL;
239         run_retval = VBERROR_SIMULATED;
240         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
241                    VBNV_RECOVERY_EC_SOFTWARE_SYNC, "Stay in RO fail");
242
243         ResetMocks();
244         shared->flags |= VBSD_LF_USE_RO_NORMAL;
245         protect_retval = VBERROR_SIMULATED;
246         test_ssync(VBERROR_SIMULATED,
247                    VBNV_RECOVERY_EC_PROTECT, "Protect error");
248
249         /* No longer check for shutdown requested */
250         ResetMocks();
251         shared->flags |= VBSD_LF_USE_RO_NORMAL;
252         shutdown_request_calls_left = 0;
253         test_ssync(0, 0, "AP-RO shutdown requested");
254
255         /* Calculate hashes */
256         ResetMocks();
257         mock_ec_hash_size = 0;
258         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
259                    VBNV_RECOVERY_EC_HASH_FAILED, "Bad EC hash");
260
261         ResetMocks();
262         mock_ec_hash_size = 16;
263         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
264                    VBNV_RECOVERY_EC_HASH_SIZE, "Bad EC hash size");
265
266         ResetMocks();
267         want_ec_hash_size = 0;
268         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
269                    VBNV_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash");
270
271         ResetMocks();
272         want_ec_hash_size = 16;
273         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
274                    VBNV_RECOVERY_EC_EXPECTED_HASH,
275                    "Bad precalculated hash size");
276
277         ResetMocks();
278         mock_in_rw = 1;
279         want_ec_hash_size = -1;
280         test_ssync(0, 0, "No precomputed hash");
281
282         ResetMocks();
283         want_ec_hash_size = -1;
284         get_expected_retval = VBERROR_SIMULATED;
285         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
286                    VBNV_RECOVERY_EC_EXPECTED_IMAGE, "Can't fetch image");
287
288         /* Updates required */
289         ResetMocks();
290         mock_in_rw = 1;
291         want_ec_hash[0]++;
292         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
293                    VBNV_RECOVERY_EC_HASH_MISMATCH,
294                    "Precalculated hash mismatch");
295
296         ResetMocks();
297         mock_in_rw = 1;
298         mock_ec_hash[0]++;
299         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
300                    0, "Pending update needs reboot");
301
302         ResetMocks();
303         mock_ec_hash[0]++;
304         test_ssync(0, 0, "Update without reboot");
305         TEST_EQ(ec_protected, 1, "  ec protected");
306         TEST_EQ(ec_run_image, 1, "  ec run image");
307         TEST_EQ(ec_updated, 1, "  ec updated");
308
309         ResetMocks();
310         mock_ec_hash[0]++;
311         update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
312         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
313                    0, "Reboot after update");
314         TEST_EQ(ec_updated, 1, "  ec updated");
315
316         ResetMocks();
317         mock_ec_hash[0]++;
318         update_retval = VBERROR_SIMULATED;
319         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
320                    VBNV_RECOVERY_EC_UPDATE, "Update failed");
321
322         ResetMocks();
323         mock_ec_hash[0]++;
324         shared->flags |= VBSD_EC_SLOW_UPDATE;
325         test_ssync(0, 0, "Slow update");
326         TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");
327
328         /* RW cases, no update */
329         ResetMocks();
330         mock_in_rw = 1;
331         test_ssync(0, 0, "AP-RW, EC-RW");
332
333         ResetMocks();
334         test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW");
335         TEST_EQ(ec_protected, 1, "  ec protected");
336         TEST_EQ(ec_run_image, 1, "  ec run image");
337         TEST_EQ(ec_updated, 0, "  ec updated");
338
339         ResetMocks();
340         run_retval = VBERROR_SIMULATED;
341         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
342                    VBNV_RECOVERY_EC_JUMP_RW, "Jump to RW fail");
343
344         ResetMocks();
345         run_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
346         test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
347                    0, "Jump to RW fail because locked");
348
349         ResetMocks();
350         protect_retval = VBERROR_SIMULATED;
351         test_ssync(VBERROR_SIMULATED,
352                    VBNV_RECOVERY_EC_PROTECT, "Protect error");
353
354         /* No longer check for shutdown requested */
355         ResetMocks();
356         shutdown_request_calls_left = 0;
357         test_ssync(0, 0,
358                    "AP-RW, EC-RO -> EC-RW shutdown requested");
359
360         ResetMocks();
361         mock_in_rw = 1;
362         shutdown_request_calls_left = 0;
363         test_ssync(0, 0, "AP-RW shutdown requested");
364 }
365
366 int main(void)
367 {
368         VbSoftwareSyncTest();
369
370         if (vboot_api_stub_check_memory())
371                 return 255;
372
373         return gTestSuccess ? 0 : 255;
374 }