~ubuntu-branches/ubuntu/trusty/vboot-utils/trusty

« back to all changes in this revision

Viewing changes to firmware/lib/vboot_api_kernel.c

  • Committer: Package Import Robot
  • Author(s): Antonio Terceiro
  • Date: 2012-12-16 11:03:40 UTC
  • Revision ID: package-import@ubuntu.com-20121216110340-f7wcseecbc9jed5l
Tags: upstream-0~20121212
ImportĀ upstreamĀ versionĀ 0~20121212

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2012 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
 * High-level firmware wrapper API - entry points for kernel selection
 
6
 */
 
7
 
 
8
#include "gbb_header.h"
 
9
#include "load_kernel_fw.h"
 
10
#include "rollback_index.h"
 
11
#include "utility.h"
 
12
#include "vboot_api.h"
 
13
#include "vboot_audio.h"
 
14
#include "vboot_common.h"
 
15
#include "vboot_display.h"
 
16
#include "vboot_nvstorage.h"
 
17
 
 
18
 
 
19
/* Global variables */
 
20
static VbNvContext vnc;
 
21
 
 
22
 
 
23
#ifdef CHROMEOS_ENVIRONMENT
 
24
/* Global variable accessors for unit tests */
 
25
VbNvContext* VbApiKernelGetVnc(void) {
 
26
  return &vnc;
 
27
}
 
28
#endif
 
29
 
 
30
 
 
31
/* Set recovery request */
 
32
static void VbSetRecoveryRequest(uint32_t recovery_request) {
 
33
  VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request));
 
34
  VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request);
 
35
}
 
36
 
 
37
 
 
38
/* Attempt loading a kernel from the specified type(s) of disks.  If
 
39
 * successful, sets p->disk_handle to the disk for the kernel and returns
 
40
 * VBERROR_SUCCESS.
 
41
 *
 
42
 * Returns VBERROR_NO_DISK_FOUND if no disks of the specified type were found.
 
43
 *
 
44
 * May return other VBERROR_ codes for other failures. */
 
45
uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
 
46
                         uint32_t get_info_flags) {
 
47
  VbError_t retval = VBERROR_UNKNOWN;
 
48
  VbDiskInfo* disk_info = NULL;
 
49
  uint32_t disk_count = 0;
 
50
  uint32_t i;
 
51
 
 
52
  VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n",
 
53
          (unsigned)get_info_flags));
 
54
 
 
55
  p->disk_handle = NULL;
 
56
 
 
57
  /* Find disks */
 
58
  if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
 
59
                                         get_info_flags))
 
60
    disk_count = 0;
 
61
 
 
62
  VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count));
 
63
  if (0 == disk_count) {
 
64
    VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK);
 
65
    return VBERROR_NO_DISK_FOUND;
 
66
  }
 
67
 
 
68
  /* Loop over disks */
 
69
  for (i = 0; i < disk_count; i++) {
 
70
    VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i));
 
71
    /* Sanity-check what we can. FWIW, VbTryLoadKernel() is always called
 
72
     * with only a single bit set in get_info_flags
 
73
     */
 
74
    if (512 != disk_info[i].bytes_per_lba || /* cgptlib restriction */
 
75
        32 > disk_info[i].lba_count ||       /* ditto */
 
76
        get_info_flags != disk_info[i].flags) { /* got only what we asked for */
 
77
      VBDEBUG(("  skipping: bytes_per_lba=%lld lba_count=%lld flags=0x%x\n",
 
78
               disk_info[i].bytes_per_lba, disk_info[i].lba_count,
 
79
               disk_info[i].flags));
 
80
      continue;
 
81
    }
 
82
    p->disk_handle = disk_info[i].handle;
 
83
    p->bytes_per_lba = disk_info[i].bytes_per_lba;
 
84
    p->ending_lba = disk_info[i].lba_count - 1;
 
85
    retval = LoadKernel(p);
 
86
    VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", retval));
 
87
 
 
88
    /* Stop now if we found a kernel */
 
89
    /* TODO: If recovery requested, should track the farthest we get, instead
 
90
     * of just returning the value from the last disk attempted. */
 
91
    if (VBERROR_SUCCESS == retval)
 
92
      break;
 
93
  }
 
94
 
 
95
  /* If we didn't find any good kernels, don't return a disk handle. */
 
96
  if (VBERROR_SUCCESS != retval) {
 
97
    VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_KERNEL);
 
98
    p->disk_handle = NULL;
 
99
  }
 
100
 
 
101
  VbExDiskFreeInfo(disk_info, p->disk_handle);
 
102
 
 
103
  /* Pass through return code.  Recovery reason (if any) has already been set
 
104
   * by LoadKernel(). */
 
105
  return retval;
 
106
}
 
107
 
 
108
#define CONFIRM_KEY_DELAY 20  /* Check confirm screen keys every 20ms */
 
109
 
 
110
/* Ask the user to confirm something. We should display whatever the question
 
111
 * is first, then call this. ESC is always "no", ENTER is always "yes", and
 
112
 * we'll specify what SPACE means. We don't return until one of those keys is
 
113
 * pressed, or until asked to shut down.
 
114
 *
 
115
 * Returns: 1=yes, 0=no, -1 = shutdown.
 
116
 */
 
117
static int VbUserConfirms(VbCommonParams* cparams, int space_means_no) {
 
118
  uint32_t key;
 
119
 
 
120
  VBDEBUG(("Entering %s(%d)\n", __func__, space_means_no));
 
121
 
 
122
  /* Await further instructions */
 
123
  while (1) {
 
124
    if (VbExIsShutdownRequested())
 
125
      return -1;
 
126
    key = VbExKeyboardRead();
 
127
    switch (key) {
 
128
    case '\r':
 
129
      VBDEBUG(("%s() - Yes (1)\n", __func__));
 
130
      return 1;
 
131
      break;
 
132
    case ' ':
 
133
      VBDEBUG(("%s() - Space (%s)\n", __func__, space_means_no));
 
134
      if (space_means_no)
 
135
        return 0;
 
136
      break;
 
137
    case 0x1b:
 
138
      VBDEBUG(("%s() - No (0)\n", __func__));
 
139
      return 0;
 
140
      break;
 
141
    default:
 
142
      VbCheckDisplayKey(cparams, key, &vnc);
 
143
    }
 
144
    VbExSleepMs(CONFIRM_KEY_DELAY);
 
145
  }
 
146
  /* not reached, but compiler will complain without it */
 
147
  return -1;
 
148
}
 
149
 
 
150
/* Handle a normal boot. */
 
151
VbError_t VbBootNormal(VbCommonParams* cparams, LoadKernelParams* p) {
 
152
  /* Boot from fixed disk only */
 
153
  VBDEBUG(("Entering %s()\n", __func__));
 
154
  return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
 
155
}
 
156
 
 
157
/* Handle a developer-mode boot */
 
158
VbError_t VbBootDeveloper(VbCommonParams* cparams, LoadKernelParams* p) {
 
159
  GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
 
160
  VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
 
161
  uint32_t allow_usb = 0, allow_legacy = 0;
 
162
  VbAudioContext* audio = 0;
 
163
 
 
164
  VBDEBUG(("Entering %s()\n", __func__));
 
165
 
 
166
  /* Check if USB booting is allowed */
 
167
  VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
 
168
  VbNvGet(&vnc, VBNV_DEV_BOOT_LEGACY, &allow_legacy);
 
169
  /* Handle GBB flag override */
 
170
  if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
 
171
    allow_usb = 1;
 
172
  if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
 
173
    allow_legacy = 1;
 
174
 
 
175
  /* Show the dev mode warning screen */
 
176
  VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
 
177
 
 
178
  /* Get audio/delay context */
 
179
  audio = VbAudioOpen(cparams);
 
180
 
 
181
  /* We'll loop until we finish the delay or are interrupted */
 
182
  do {
 
183
    uint32_t key;
 
184
 
 
185
    if (VbExIsShutdownRequested()) {
 
186
      VBDEBUG(("VbBootDeveloper() - shutdown is requested!\n"));
 
187
      VbAudioClose(audio);
 
188
      return VBERROR_SHUTDOWN_REQUESTED;
 
189
    }
 
190
 
 
191
    key = VbExKeyboardRead();
 
192
    switch (key) {
 
193
      case 0:
 
194
        /* nothing pressed */
 
195
        break;
 
196
      case '\r':
 
197
        /* Enter only disables the virtual dev switch if allowed by GBB */
 
198
        if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
 
199
          break;
 
200
      case ' ':
 
201
        /* See if we should disable the virtual dev-mode switch. */
 
202
        VBDEBUG(("%s shared->flags=0x%x\n", __func__, shared->flags));
 
203
        if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
 
204
            shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
 
205
          VbAudioClose(audio);    /* Stop the countdown while we go ask... */
 
206
          if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
 
207
            /* TONORM won't work (only for non-shipping devices). */
 
208
            VBDEBUG(("%s() - TONORM rejected by GBB_FLAG_FORCE_DEV_SWITCH_ON\n",
 
209
                     __func__));
 
210
            VbExDisplayDebugInfo("WARNING: TONORM is prohibited by "
 
211
                                 "GBB_FLAG_FORCE_DEV_SWITCH_ON.\n\n");
 
212
            VbExBeep(120, 400);
 
213
            break;
 
214
          }
 
215
          VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_TO_NORM, 0, &vnc);
 
216
          switch (VbUserConfirms(cparams, 0)) { /* Ignore space */
 
217
          case 1:
 
218
            VBDEBUG(("%s() - leaving dev-mode...\n", __func__));
 
219
            VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 1);
 
220
            VbDisplayScreen(cparams, VB_SCREEN_TO_NORM_CONFIRMED, 0, &vnc);
 
221
            VbExSleepMs(5000);
 
222
            return VBERROR_TPM_REBOOT_REQUIRED;
 
223
          case -1:
 
224
            VBDEBUG(("%s() - shutdown requested\n", __func__));
 
225
            return VBERROR_SHUTDOWN_REQUESTED;
 
226
          default:                      /* stay in dev-mode */
 
227
            VBDEBUG(("%s() - stay in dev-mode\n", __func__));
 
228
            VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
 
229
            audio = VbAudioOpen(cparams); /* Start new countdown */
 
230
          }
 
231
        } else {
 
232
          /* No virtual dev-mode switch, so go directly to recovery mode */
 
233
          VBDEBUG(("%s() - going to recovery\n", __func__));
 
234
          VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_SCREEN);
 
235
          VbAudioClose(audio);
 
236
          return VBERROR_LOAD_KERNEL_RECOVERY;
 
237
        }
 
238
        break;
 
239
      case 0x04:
 
240
        /* Ctrl+D = dismiss warning; advance to timeout */
 
241
        VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+D; skip delay\n"));
 
242
        goto fallout;
 
243
        break;
 
244
      case 0x0c:
 
245
        VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+L; Try legacy boot\n"));
 
246
        /* If VbExLegacy() succeeds, it will never return.
 
247
         * If it returns, beep.
 
248
         */
 
249
        if (allow_legacy)
 
250
          VbExLegacy();
 
251
        else
 
252
          VBDEBUG(("VbBootDeveloper() - Legacy boot is disabled\n"));
 
253
 
 
254
        VbExBeep(120, 400);
 
255
        VbExSleepMs(120);
 
256
        VbExBeep(120, 400);
 
257
        break;
 
258
      /* The Ctrl-Enter is special for Lumpy test purpose. */
 
259
      case VB_KEY_CTRL_ENTER:
 
260
      case 0x15:
 
261
        /* Ctrl+U = try USB boot, or beep if failure */
 
262
        VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+U; try USB\n"));
 
263
        if (!allow_usb) {
 
264
          VBDEBUG(("VbBootDeveloper() - USB booting is disabled\n"));
 
265
          VbExDisplayDebugInfo("WARNING: Booting from external media (USB/SD) "
 
266
                               "has not been enabled. Refer to the "
 
267
                               "developer-mode documentation for details.\n");
 
268
          VbExBeep(120, 400);
 
269
          VbExSleepMs(120);
 
270
          VbExBeep(120, 400);
 
271
        } else {
 
272
          /* Clear the screen to show we get the Ctrl+U key press. */
 
273
          VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
274
          if (VBERROR_SUCCESS ==
 
275
              VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE)) {
 
276
            VBDEBUG(("VbBootDeveloper() - booting USB\n"));
 
277
            VbAudioClose(audio);
 
278
            return VBERROR_SUCCESS;
 
279
          } else {
 
280
            VBDEBUG(("VbBootDeveloper() - no kernel found on USB\n"));
 
281
            VbExBeep(250, 200);
 
282
            VbExSleepMs(120);
 
283
            /* Clear recovery requests from failed kernel loading, so
 
284
             * that powering off at this point doesn't put us into
 
285
             * recovery mode. */
 
286
            VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
 
287
            /* Show the dev mode warning screen again */
 
288
            VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
 
289
          }
 
290
        }
 
291
        break;
 
292
      default:
 
293
        VBDEBUG(("VbBootDeveloper() - pressed key %d\n", key));
 
294
        VbCheckDisplayKey(cparams, key, &vnc);
 
295
        break;
 
296
    }
 
297
 
 
298
  } while( VbAudioLooping(audio) );
 
299
 
 
300
fallout:
 
301
  /* Timeout or Ctrl+D; attempt loading from fixed disk */
 
302
  VBDEBUG(("VbBootDeveloper() - trying fixed disk\n"));
 
303
  VbAudioClose(audio);
 
304
  return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
 
305
}
 
306
 
 
307
/* Delay in recovery mode */
 
308
#define REC_DISK_DELAY 1000     /* Check disks every 1s */
 
309
#define REC_KEY_DELAY  20       /* Check keys every 20ms */
 
310
 
 
311
/* Handle a recovery-mode boot */
 
312
VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
 
313
  VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
 
314
  uint32_t retval;
 
315
  uint32_t key;
 
316
  int i;
 
317
 
 
318
  VBDEBUG(("VbBootRecovery() start\n"));
 
319
 
 
320
  /* If the dev-mode switch is off and the user didn't press the recovery
 
321
   * button, require removal of all external media. */
 
322
  if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
 
323
      !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
 
324
    VbDiskInfo* disk_info = NULL;
 
325
    uint32_t disk_count = 0;
 
326
 
 
327
    VBDEBUG(("VbBootRecovery() forcing device removal\n"));
 
328
 
 
329
    while (1) {
 
330
      if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
 
331
                                             VB_DISK_FLAG_REMOVABLE))
 
332
        disk_count = 0;
 
333
      VbExDiskFreeInfo(disk_info, NULL);
 
334
 
 
335
      if (0 == disk_count) {
 
336
        VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
337
        break;
 
338
      }
 
339
 
 
340
      VBDEBUG(("VbBootRecovery() waiting for %d disks to be removed\n",
 
341
               (int)disk_count));
 
342
 
 
343
      VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE, 0, &vnc);
 
344
 
 
345
      /* Scan keyboard more frequently than media, since x86 platforms
 
346
       * don't like to scan USB too rapidly. */
 
347
      for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
 
348
        VbCheckDisplayKey(cparams, VbExKeyboardRead(), &vnc);
 
349
        if (VbExIsShutdownRequested())
 
350
          return VBERROR_SHUTDOWN_REQUESTED;
 
351
        VbExSleepMs(REC_KEY_DELAY);
 
352
      }
 
353
    }
 
354
  }
 
355
 
 
356
  /* Loop and wait for a recovery image */
 
357
  while (1) {
 
358
    VBDEBUG(("VbBootRecovery() attempting to load kernel2\n"));
 
359
    retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE);
 
360
 
 
361
    /* Clear recovery requests from failed kernel loading, since we're
 
362
     * already in recovery mode.  Do this now, so that powering off after
 
363
     * inserting an invalid disk doesn't leave us stuck in recovery mode. */
 
364
    VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
 
365
 
 
366
    if (VBERROR_SUCCESS == retval)
 
367
      break;                            /* Found a recovery kernel */
 
368
 
 
369
    VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ?
 
370
                    VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD,
 
371
                    0, &vnc);
 
372
 
 
373
    /* Scan keyboard more frequently than media, since x86 platforms don't like
 
374
     * to scan USB too rapidly. */
 
375
    for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
 
376
      key = VbExKeyboardRead();
 
377
      /* We might want to enter dev-mode from the Insert screen if... */
 
378
      if (key == 0x04 &&                /* user pressed Ctrl-D */
 
379
          shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH && /* we can do that */
 
380
          !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && /* not in dev-mode */
 
381
          (shared->flags & VBSD_BOOT_REC_SWITCH_ON) && /* user forced rec */
 
382
          VbExTrustEC()) {                             /* EC isn't pwned */
 
383
        /* Ask the user to confirm entering dev-mode */
 
384
        VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_TO_DEV, 0, &vnc);
 
385
        switch (VbUserConfirms(cparams, 1)) { /* SPACE means no */
 
386
        case 1:
 
387
          VBDEBUG(("%s() - Enabling dev-mode...\n", __func__));
 
388
          if (TPM_SUCCESS != SetVirtualDevMode(1))
 
389
            return VBERROR_TPM_SET_BOOT_MODE_STATE;
 
390
          VBDEBUG(("%s() - Reboot so it will take effect\n", __func__));
 
391
          return VBERROR_TPM_REBOOT_REQUIRED;
 
392
        case -1:
 
393
          VBDEBUG(("%s() - Shutdown requested\n", __func__));
 
394
          return VBERROR_SHUTDOWN_REQUESTED;
 
395
        default:                        /* zero, actually */
 
396
          VBDEBUG(("%s() - Not enabling dev-mode\n", __func__));
 
397
          /* Jump out of the outer loop to refresh the display quickly. */
 
398
          i = 4;
 
399
          break;
 
400
        }
 
401
      } else
 
402
        VbCheckDisplayKey(cparams, key, &vnc);
 
403
      if (VbExIsShutdownRequested())
 
404
        return VBERROR_SHUTDOWN_REQUESTED;
 
405
      VbExSleepMs(REC_KEY_DELAY);
 
406
    }
 
407
  }
 
408
 
 
409
  return VBERROR_SUCCESS;
 
410
}
 
411
 
 
412
/* Wrapper around VbExEcProtectRW() which sets recovery reason on error */
 
413
static VbError_t EcProtectRW(void) {
 
414
  int rv = VbExEcProtectRW();
 
415
 
 
416
  if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
 
417
    VBDEBUG(("VbExEcProtectRW() needs reboot\n"));
 
418
  } else if (rv != VBERROR_SUCCESS) {
 
419
    VBDEBUG(("VbExEcProtectRW() returned %d\n", rv));
 
420
    VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
 
421
  }
 
422
  return rv;
 
423
}
 
424
 
 
425
VbError_t VbEcSoftwareSync(VbCommonParams* cparams) {
 
426
  VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
 
427
  int in_rw = 0;
 
428
  int rv;
 
429
  const uint8_t *ec_hash;
 
430
  int ec_hash_size;
 
431
  const uint8_t *expected;
 
432
  int expected_size;
 
433
  uint8_t expected_hash[SHA256_DIGEST_SIZE];
 
434
  int need_update;
 
435
  int i;
 
436
 
 
437
  /* Determine whether the EC is in RO or RW */
 
438
  rv = VbExEcRunningRW(&in_rw);
 
439
 
 
440
  if (shared->recovery_reason) {
 
441
    /* Recovery mode; just verify the EC is in RO code */
 
442
    if (rv == VBERROR_SUCCESS && in_rw == 1) {
 
443
      /* EC is definitely in RW firmware.  We want it in read-only code, so
 
444
       * preserve the current recovery reason and reboot.
 
445
       *
 
446
       * We don't reboot on error or unknown EC code, because we could end
 
447
       * up in an endless reboot loop.  If we had some way to track that we'd
 
448
       * already rebooted for this reason, we could retry only once. */
 
449
      VBDEBUG(("VbEcSoftwareSync() - want recovery but got EC-RW\n"));
 
450
      VbSetRecoveryRequest(shared->recovery_reason);
 
451
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
452
    }
 
453
 
 
454
    VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
 
455
    return VBERROR_SUCCESS;
 
456
  }
 
457
 
 
458
  /* Not in recovery.  If we couldn't determine where the EC was,
 
459
   * reboot to recovery. */
 
460
  if (rv != VBERROR_SUCCESS) {
 
461
    VBDEBUG(("VbEcSoftwareSync() - VbEcSoftwareSync() returned %d\n", rv));
 
462
    VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
 
463
    return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
464
  }
 
465
 
 
466
  /* If AP is read-only normal, EC should be in its RO code also. */
 
467
  if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
 
468
    /* If EC is in RW code, request reboot back to RO */
 
469
    if (in_rw == 1) {
 
470
      VBDEBUG(("VbEcSoftwareSync() - want RO-normal but got EC-RW\n"));
 
471
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
472
    }
 
473
 
 
474
    /* Protect the RW flash and stay in EC-RO */
 
475
    rv = EcProtectRW();
 
476
    if (rv != VBERROR_SUCCESS)
 
477
      return rv;
 
478
 
 
479
    rv = VbExEcStayInRO();
 
480
    if (rv != VBERROR_SUCCESS) {
 
481
      VBDEBUG(("VbEcSoftwareSync() - VbExEcStayInRO() returned %d\n", rv));
 
482
      VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
 
483
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
484
    }
 
485
 
 
486
    VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
 
487
 
 
488
    /* If shutdown is requested, just power the AP back off.  This covers the
 
489
     * case where the lid is closed when then system boots. */
 
490
    if (VbExIsShutdownRequested()) {
 
491
      VBDEBUG(("VbEcSoftwareSync() sees shutdown-requested\n"));
 
492
      return VBERROR_SHUTDOWN_REQUESTED;
 
493
    }
 
494
 
 
495
    return VBERROR_SUCCESS;
 
496
  }
 
497
 
 
498
  /* Get hash of EC-RW */
 
499
  rv = VbExEcHashRW(&ec_hash, &ec_hash_size);
 
500
  if (rv) {
 
501
      VBDEBUG(("VbEcSoftwareSync() - VbExEcHashRW() returned %d\n", rv));
 
502
      VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
 
503
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
504
  }
 
505
  if (ec_hash_size != SHA256_DIGEST_SIZE) {
 
506
      VBDEBUG(("VbEcSoftwareSync() - VbExEcHashRW() says size %d, not %d\n",
 
507
               ec_hash_size, SHA256_DIGEST_SIZE));
 
508
      VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
 
509
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
510
  }
 
511
 
 
512
  VBDEBUG(("EC hash:"));
 
513
  for (i = 0; i < SHA256_DIGEST_SIZE; i++)
 
514
    VBDEBUG(("%02x", ec_hash[i]));
 
515
  VBDEBUG(("\n"));
 
516
 
 
517
  /* Get expected EC-RW code. Note that we've already checked for RO_NORMAL,
 
518
   * so we know that the BIOS must be RW-A or RW-B, and therefore the EC must
 
519
   * match. */
 
520
  rv = VbExEcGetExpectedRW(
 
521
    shared->firmware_index ? VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
 
522
    &expected, &expected_size);
 
523
  if (rv) {
 
524
    VBDEBUG(("VbEcSoftwareSync() - VbExEcGetExpectedRW() returned %d\n", rv));
 
525
    VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
 
526
    return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
527
  }
 
528
  VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n", expected_size));
 
529
 
 
530
  /* Hash expected code */
 
531
  internal_SHA256(expected, expected_size, expected_hash);
 
532
  VBDEBUG(("Expected hash:"));
 
533
  for (i = 0; i < SHA256_DIGEST_SIZE; i++)
 
534
    VBDEBUG(("%02x", expected_hash[i]));
 
535
  VBDEBUG(("\n"));
 
536
 
 
537
  need_update = SafeMemcmp(ec_hash, expected_hash, SHA256_DIGEST_SIZE);
 
538
 
 
539
  /* TODO: GBB flag to override whether we need update; needed for EC
 
540
   * development */
 
541
 
 
542
  if (in_rw) {
 
543
    if (need_update) {
 
544
      /* EC is running the wrong RW code.  Reboot the EC to RO so we can update
 
545
       * it on the next boot. */
 
546
      VBDEBUG(("VbEcSoftwareSync() - in RW, need to update RW, so reboot\n"));
 
547
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
548
    }
 
549
 
 
550
    VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
 
551
    return VBERROR_SUCCESS;
 
552
  }
 
553
 
 
554
  /* Update EC if necessary */
 
555
  if (need_update) {
 
556
    VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));
 
557
 
 
558
    if (shared->flags & VBSD_EC_SLOW_UPDATE) {
 
559
      VBDEBUG(("VbEcSoftwareSync() - EC is slow. Show WAIT screen.\n"));
 
560
      /* FIXME(crosbug.com/p/12257): Ensure the VGA Option ROM is loaded! */
 
561
      VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
 
562
    }
 
563
 
 
564
    rv = VbExEcUpdateRW(expected, expected_size);
 
565
    if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
 
566
      /* Reboot required.  May need to unprotect RW before updating,
 
567
       * or may need to reboot after RW updated.  Either way, it's not
 
568
       * an error requiring recovery mode. */
 
569
      VBDEBUG(("VbEcSoftwareSync() - VbExEcUpdateRW() needs reboot\n"));
 
570
      return rv;
 
571
    } else if (rv != VBERROR_SUCCESS) {
 
572
      VBDEBUG(("VbEcSoftwareSync() - VbExEcUpdateRW() returned %d\n", rv));
 
573
      VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
 
574
      return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
575
    }
 
576
 
 
577
    /*
 
578
     * TODO: should ask EC to recompute its hash to verify it's correct
 
579
     * before continuing?
 
580
     */
 
581
  }
 
582
 
 
583
  /* Protect EC-RW flash */
 
584
  rv = EcProtectRW();
 
585
  if (rv != VBERROR_SUCCESS)
 
586
    return rv;
 
587
 
 
588
  /* Tell EC to jump to its RW code */
 
589
  VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
 
590
  rv = VbExEcJumpToRW();
 
591
  if (rv != VBERROR_SUCCESS) {
 
592
    VBDEBUG(("VbEcSoftwareSync() - VbExEcJumpToRW() returned %d\n", rv));
 
593
    VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
 
594
    return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
 
595
  }
 
596
 
 
597
  VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
 
598
 
 
599
  /* If shutdown is requested, just power the AP back off.  This covers the
 
600
   * case where the lid is closed when then system boots. */
 
601
  if (VbExIsShutdownRequested()) {
 
602
    VBDEBUG(("VbEcSoftwareSync() sees shutdown-requested\n"));
 
603
    return VBERROR_SHUTDOWN_REQUESTED;
 
604
  }
 
605
 
 
606
  return VBERROR_SUCCESS;
 
607
}
 
608
 
 
609
 
 
610
VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
 
611
                                VbSelectAndLoadKernelParams* kparams) {
 
612
  VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
 
613
  VbError_t retval = VBERROR_SUCCESS;
 
614
  LoadKernelParams p;
 
615
  uint32_t tpm_status = 0;
 
616
 
 
617
  /* Start timer */
 
618
  shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
 
619
 
 
620
  VbExNvStorageRead(vnc.raw);
 
621
  VbNvSetup(&vnc);
 
622
 
 
623
  /* Clear output params in case we fail */
 
624
  kparams->disk_handle = NULL;
 
625
  kparams->partition_number = 0;
 
626
  kparams->bootloader_address = 0;
 
627
  kparams->bootloader_size = 0;
 
628
  Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
 
629
 
 
630
  /* Do EC software sync if necessary */
 
631
  if (shared->flags & VBSD_EC_SOFTWARE_SYNC) {
 
632
    retval = VbEcSoftwareSync(cparams);
 
633
    if (retval != VBERROR_SUCCESS)
 
634
      goto VbSelectAndLoadKernel_exit;
 
635
  }
 
636
 
 
637
  /* Read the kernel version from the TPM.  Ignore errors in recovery mode. */
 
638
  tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
 
639
  if (0 != tpm_status) {
 
640
    VBDEBUG(("Unable to get kernel versions from TPM\n"));
 
641
    if (!shared->recovery_reason) {
 
642
      VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR);
 
643
      retval = VBERROR_TPM_READ_KERNEL;
 
644
      goto VbSelectAndLoadKernel_exit;
 
645
    }
 
646
  }
 
647
  shared->kernel_version_tpm_start = shared->kernel_version_tpm;
 
648
 
 
649
  /* Fill in params for calls to LoadKernel() */
 
650
  Memset(&p, 0, sizeof(p));
 
651
  p.shared_data_blob = cparams->shared_data_blob;
 
652
  p.shared_data_size = cparams->shared_data_size;
 
653
  p.gbb_data = cparams->gbb_data;
 
654
  p.gbb_size = cparams->gbb_size;
 
655
 
 
656
  /*
 
657
   * this could be set to NULL, in which case the vboot header information
 
658
   * about the load address and size will be used
 
659
   */
 
660
  p.kernel_buffer = kparams->kernel_buffer;
 
661
  p.kernel_buffer_size = kparams->kernel_buffer_size;
 
662
 
 
663
  p.nv_context = &vnc;
 
664
  p.boot_flags = 0;
 
665
  if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON)
 
666
    p.boot_flags |= BOOT_FLAG_DEVELOPER;
 
667
 
 
668
  /* Handle separate normal and developer firmware builds. */
 
669
#if defined(VBOOT_FIRMWARE_TYPE_NORMAL)
 
670
  /* Normal-type firmware always acts like the dev switch is off. */
 
671
  p.boot_flags &= ~BOOT_FLAG_DEVELOPER;
 
672
#elif defined(VBOOT_FIRMWARE_TYPE_DEVELOPER)
 
673
  /* Developer-type firmware fails if the dev switch is off. */
 
674
  if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) {
 
675
    /* Dev firmware should be signed with a key that only verifies
 
676
     * when the dev switch is on, so we should never get here. */
 
677
    VBDEBUG(("Developer firmware called with dev switch off!\n"));
 
678
    VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
 
679
    retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH;
 
680
    goto VbSelectAndLoadKernel_exit;
 
681
  }
 
682
#else
 
683
  /* Recovery firmware, or merged normal+developer firmware.  No
 
684
   * need to override flags. */
 
685
#endif
 
686
 
 
687
  /* Select boot path */
 
688
  if (shared->recovery_reason) {
 
689
    /* Recovery boot */
 
690
    p.boot_flags |= BOOT_FLAG_RECOVERY;
 
691
    retval = VbBootRecovery(cparams, &p);
 
692
    VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
693
 
 
694
  } else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
 
695
    /* Developer boot */
 
696
    retval = VbBootDeveloper(cparams, &p);
 
697
    VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
698
 
 
699
  } else {
 
700
    /* Normal boot */
 
701
    retval = VbBootNormal(cparams, &p);
 
702
 
 
703
    if ((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED)) {
 
704
      /* Special cases for when we're trying a new firmware B.  These are
 
705
       * needed because firmware updates also usually change the kernel key,
 
706
       * which means that the B firmware can only boot a new kernel, and the
 
707
       * old firmware in A can only boot the previous kernel. */
 
708
 
 
709
      /* Don't advance the TPM if we're trying a new firmware B, because we
 
710
       * don't yet know if the new kernel will successfully boot.  We still
 
711
       * want to be able to fall back to the previous firmware+kernel if the
 
712
       * new firmware+kernel fails. */
 
713
 
 
714
      /* If we found only invalid kernels, reboot and try again.  This allows
 
715
       * us to fall back to the previous firmware+kernel instead of giving up
 
716
       * and going to recovery mode right away.  We'll still go to recovery
 
717
       * mode if we run out of tries and the old firmware can't find a kernel
 
718
       * it likes. */
 
719
      if (VBERROR_INVALID_KERNEL_FOUND == retval) {
 
720
        VBDEBUG(("Trying firmware B, and only found invalid kernels.\n"));
 
721
        VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
 
722
        goto VbSelectAndLoadKernel_exit;
 
723
      }
 
724
    } else {
 
725
      /* Not trying a new firmware B. */
 
726
      /* See if we need to update the TPM. */
 
727
      VBDEBUG(("Checking if TPM kernel version needs advancing\n"));
 
728
      if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) {
 
729
        tpm_status = RollbackKernelWrite(shared->kernel_version_tpm);
 
730
        if (0 != tpm_status) {
 
731
          VBDEBUG(("Error writing kernel versions to TPM.\n"));
 
732
          VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR);
 
733
          retval = VBERROR_TPM_WRITE_KERNEL;
 
734
          goto VbSelectAndLoadKernel_exit;
 
735
        }
 
736
      }
 
737
    }
 
738
  }
 
739
 
 
740
  if (VBERROR_SUCCESS != retval)
 
741
    goto VbSelectAndLoadKernel_exit;
 
742
 
 
743
  /* Save disk parameters */
 
744
  kparams->disk_handle = p.disk_handle;
 
745
  kparams->partition_number = (uint32_t)p.partition_number;
 
746
  kparams->bootloader_address = p.bootloader_address;
 
747
  kparams->bootloader_size = (uint32_t)p.bootloader_size;
 
748
  Memcpy(kparams->partition_guid, p.partition_guid,
 
749
         sizeof(kparams->partition_guid));
 
750
 
 
751
  /* Lock the kernel versions.  Ignore errors in recovery mode. */
 
752
  tpm_status = RollbackKernelLock();
 
753
  if (0 != tpm_status) {
 
754
    VBDEBUG(("Error locking kernel versions.\n"));
 
755
    if (!shared->recovery_reason) {
 
756
      VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR);
 
757
      retval = VBERROR_TPM_LOCK_KERNEL;
 
758
      goto VbSelectAndLoadKernel_exit;
 
759
    }
 
760
  }
 
761
 
 
762
VbSelectAndLoadKernel_exit:
 
763
 
 
764
  VbNvTeardown(&vnc);
 
765
  if (vnc.raw_changed)
 
766
    VbExNvStorageWrite(vnc.raw);
 
767
 
 
768
  /* Stop timer */
 
769
  shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
 
770
 
 
771
  kparams->kernel_buffer = p.kernel_buffer;
 
772
  kparams->kernel_buffer_size = p.kernel_buffer_size;
 
773
 
 
774
  VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
 
775
 
 
776
  /* Pass through return value from boot path */
 
777
  return retval;
 
778
}