Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: vboot_firmware/lib/load_kernel_fw.c

Issue 2735004: Uses TPM return codes. (Closed) Base URL: ssh://gitrw.chromium.org/vboot_reference.git
Patch Set: Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « vboot_firmware/include/rollback_index.h ('k') | vboot_firmware/lib/rollback_index.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be 2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. 3 * found in the LICENSE file.
4 * 4 *
5 * Functions for loading a kernel from disk. 5 * Functions for loading a kernel from disk.
6 * (Firmware portion) 6 * (Firmware portion)
7 */ 7 */
8 8
9 #include "load_kernel_fw.h" 9 #include "load_kernel_fw.h"
10 10
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 e->ending_lba - e->starting_lba + 1); 56 e->ending_lba - e->starting_lba + 1);
57 printf("Hacking attributes for kernel partition %d\n", i); 57 printf("Hacking attributes for kernel partition %d\n", i);
58 #endif 58 #endif
59 59
60 SetEntryPriority(e, 2); 60 SetEntryPriority(e, 2);
61 SetEntrySuccessful(e, 1); 61 SetEntrySuccessful(e, 1);
62 } 62 }
63 } 63 }
64 64
65 65
66 int AllocAndReadGptData(GptData *gptdata) { 66 /* Allocates and reads GPT data from the drive. The sector_bytes and
67 /* Allocates and reads GPT data from the drive. The sector_bytes and 67 * drive_sectors fields should be filled on input. The primary and
68 * drive_sectors fields should be filled on input. The primary and 68 * secondary header and entries are filled on output.
69 * secondary header and entries are filled on output. 69 *
70 * 70 * Returns 0 if successful, 1 if error. */
71 * Returns 0 if successful, 1 if error. */ 71 int AllocAndReadGptData(GptData* gptdata) {
72 72
73 uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes; 73 uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes;
74 74
75 /* No data to be written yet */ 75 /* No data to be written yet */
76 gptdata->modified = 0; 76 gptdata->modified = 0;
77 77
78 /* Allocate all buffers */ 78 /* Allocate all buffers */
79 gptdata->primary_header = (uint8_t*)Malloc(gptdata->sector_bytes); 79 gptdata->primary_header = (uint8_t*)Malloc(gptdata->sector_bytes);
80 gptdata->secondary_header = (uint8_t*)Malloc(gptdata->sector_bytes); 80 gptdata->secondary_header = (uint8_t*)Malloc(gptdata->sector_bytes);
81 gptdata->primary_entries = (uint8_t*)Malloc(GPT_ENTRIES_SIZE); 81 gptdata->primary_entries = (uint8_t*)Malloc(GPT_ENTRIES_SIZE);
(...skipping 11 matching lines...) Expand all
93 if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1, 93 if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1,
94 entries_sectors, gptdata->secondary_entries)) 94 entries_sectors, gptdata->secondary_entries))
95 return 1; 95 return 1;
96 if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1, 96 if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1,
97 1, gptdata->secondary_header)) 97 1, gptdata->secondary_header))
98 return 1; 98 return 1;
99 99
100 return 0; 100 return 0;
101 } 101 }
102 102
103 void WriteAndFreeGptData(GptData *gptdata) { 103
104 /* Writes any changes for the GPT data back to the drive, then frees the 104 /* Writes any changes for the GPT data back to the drive, then frees
105 * buffers. */ 105 * the buffers.
106 *
107 * Returns 0 if successful, 1 if error. */
108 int WriteAndFreeGptData(GptData* gptdata) {
106 109
107 uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes; 110 uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes;
108 111
109 if (gptdata->primary_header) { 112 if (gptdata->primary_header) {
110 if (gptdata->modified & GPT_MODIFIED_HEADER1) 113 if (gptdata->modified & GPT_MODIFIED_HEADER1) {
111 BootDeviceWriteLBA(1, 1, gptdata->primary_header); 114 if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header))
115 return 1;
116 }
112 Free(gptdata->primary_header); 117 Free(gptdata->primary_header);
113 } 118 }
114 119
115 if (gptdata->primary_entries) { 120 if (gptdata->primary_entries) {
116 if (gptdata->modified & GPT_MODIFIED_ENTRIES1) 121 if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
117 BootDeviceWriteLBA(2, entries_sectors, gptdata->primary_entries); 122 if (0 != BootDeviceWriteLBA(2, entries_sectors,
123 gptdata->primary_entries))
124 return 1;
125 }
118 Free(gptdata->primary_entries); 126 Free(gptdata->primary_entries);
119 } 127 }
120 128
121 if (gptdata->secondary_entries) { 129 if (gptdata->secondary_entries) {
122 if (gptdata->modified & GPT_MODIFIED_ENTRIES2) 130 if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
123 BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1, 131 if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1,
124 entries_sectors, gptdata->secondary_entries); 132 entries_sectors, gptdata->secondary_entries))
133 return 1;
134 }
125 Free(gptdata->secondary_entries); 135 Free(gptdata->secondary_entries);
126 } 136 }
127 137
128 if (gptdata->secondary_header) { 138 if (gptdata->secondary_header) {
129 if (gptdata->modified & GPT_MODIFIED_HEADER2) 139 if (gptdata->modified & GPT_MODIFIED_HEADER2) {
130 BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1, 140 if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1,
131 1, gptdata->secondary_header); 141 gptdata->secondary_header))
132 BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1, 142 return 1;
133 gptdata->secondary_header); 143 }
134 Free(gptdata->secondary_header); 144 Free(gptdata->secondary_header);
135 } 145 }
136 /* TODO: What to do with return codes from the writes? */ 146
147 /* Success */
148 return 0;
137 } 149 }
138 150
151
139 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ 152 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
140 153
141 int LoadKernel(LoadKernelParams* params) { 154 int LoadKernel(LoadKernelParams* params) {
142 155
143 GptData gpt; 156 GptData gpt;
144 uint64_t part_start, part_size; 157 uint64_t part_start, part_size;
145 uint64_t blba = params->bytes_per_lba; 158 uint64_t blba = params->bytes_per_lba;
146 uint8_t* kbuf = NULL; 159 uint8_t* kbuf = NULL;
147 uint64_t kbuf_sectors; 160 uint64_t kbuf_sectors;
148 int found_partition = 0; 161 int found_partition = 0;
149 int good_partition = -1; 162 int good_partition = -1;
150 uint16_t tpm_kernel_key_version, tpm_kernel_version; 163 uint16_t tpm_kernel_key_version, tpm_kernel_version;
151 uint16_t lowest_kernel_key_version = 0xFFFF; 164 uint16_t lowest_kernel_key_version = 0xFFFF;
152 uint16_t lowest_kernel_version = 0xFFFF; 165 uint16_t lowest_kernel_version = 0xFFFF;
153 KernelImage *kim = NULL; 166 KernelImage *kim = NULL;
154 167
155 /* Clear output params in case we fail */ 168 /* Clear output params in case we fail */
156 params->partition_number = 0; 169 params->partition_number = 0;
157 params->bootloader_address = 0; 170 params->bootloader_address = 0;
158 params->bootloader_size = 0; 171 params->bootloader_size = 0;
159 172
160 /* Read current kernel key index from TPM. Assumes TPM is already 173 if (BOOT_MODE_NORMAL == params->boot_mode) {
161 * initialized. */ 174 /* Read current kernel key index from TPM. Assumes TPM is already
162 /* TODO: Is that a safe assumption? Normally, SetupTPM() would be called 175 * initialized. */
163 * when the RW firmware is verified. Is it harmful to call SetupTPM() 176 if (0 != GetStoredVersions(KERNEL_VERSIONS,
164 * again if it's already initialized? It'd be easier if we could just do 177 &tpm_kernel_key_version,
165 * that. */ 178 &tpm_kernel_version))
166 GetStoredVersions(KERNEL_VERSIONS, 179 return LOAD_KERNEL_RECOVERY;
167 &tpm_kernel_key_version, 180 }
168 &tpm_kernel_version);
169 181
170 do { 182 do {
171 /* Read GPT data */ 183 /* Read GPT data */
172 gpt.sector_bytes = blba; 184 gpt.sector_bytes = blba;
173 gpt.drive_sectors = params->ending_lba + 1; 185 gpt.drive_sectors = params->ending_lba + 1;
174 if (0 != AllocAndReadGptData(&gpt)) 186 if (0 != AllocAndReadGptData(&gpt))
175 break; 187 break;
176 188
177 /* Initialize GPT library */ 189 /* Initialize GPT library */
178 if (GPT_SUCCESS != GptInit(&gpt)) 190 if (GPT_SUCCESS != GptInit(&gpt))
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 RSAPublicKeyFree(kernel_sign_key); 295 RSAPublicKeyFree(kernel_sign_key);
284 296
285 /* If we're still here, the kernel is valid. */ 297 /* If we're still here, the kernel is valid. */
286 /* Save the first good partition we find; that's the one we'll boot */ 298 /* Save the first good partition we find; that's the one we'll boot */
287 if (-1 == good_partition) { 299 if (-1 == good_partition) {
288 good_partition = gpt.current_kernel; 300 good_partition = gpt.current_kernel;
289 params->partition_number = gpt.current_kernel; 301 params->partition_number = gpt.current_kernel;
290 params->bootloader_address = kim->bootloader_offset; 302 params->bootloader_address = kim->bootloader_offset;
291 params->bootloader_size = kim->bootloader_size; 303 params->bootloader_size = kim->bootloader_size;
292 304
293 /* If the good partition's key version is the same as the tpm, then 305 /* If we're in developer or recovery mode, there's no rollback
294 * the TPM doesn't need updating; we can stop now. Otherwise, we'll 306 * protection, so we can stop at the first valid kernel. */
295 * check all the other headers to see if they contain a newer key. */ 307 if (BOOT_MODE_NORMAL != params->boot_mode)
308 break;
309
310 /* Otherwise, we're in normal boot mode, so we do care about
311 * the key index in the TPM. If the good partition's key
312 * version is the same as the tpm, then the TPM doesn't need
313 * updating; we can stop now. Otherwise, we'll check all the
314 * other headers to see if they contain a newer key. */
296 if (kim->kernel_key_version == tpm_kernel_key_version && 315 if (kim->kernel_key_version == tpm_kernel_key_version &&
297 kim->kernel_version == tpm_kernel_version) 316 kim->kernel_version == tpm_kernel_version)
298 break; 317 break;
299 } 318 }
300 } /* while(GptNextKernelEntry) */ 319 } /* while(GptNextKernelEntry) */
301 } while(0); 320 } while(0);
302 321
303 /* Free kernel work and image buffers */ 322 /* Free kernel work and image buffers */
304 if (kbuf) 323 if (kbuf)
305 Free(kbuf); 324 Free(kbuf);
306 if (kim) 325 if (kim)
307 Free(kim); 326 Free(kim);
308 327
309 // Write and free GPT data 328 /* Write and free GPT data */
310 WriteAndFreeGptData(&gpt); 329 WriteAndFreeGptData(&gpt);
311 330
312 // Handle finding a good partition 331 /* Handle finding a good partition */
313 if (good_partition >= 0) { 332 if (good_partition >= 0) {
314 333
315 /* See if we need to update the TPM */ 334 if (BOOT_MODE_NORMAL == params->boot_mode) {
316 if ((lowest_kernel_key_version > tpm_kernel_key_version) || 335 /* See if we need to update the TPM, for normal boot mode only. */
317 (lowest_kernel_key_version == tpm_kernel_key_version && 336 if ((lowest_kernel_key_version > tpm_kernel_key_version) ||
318 lowest_kernel_version > tpm_kernel_version)) { 337 (lowest_kernel_key_version == tpm_kernel_key_version &&
319 WriteStoredVersions(KERNEL_VERSIONS, 338 lowest_kernel_version > tpm_kernel_version)) {
320 lowest_kernel_key_version, 339 if (0 != WriteStoredVersions(KERNEL_VERSIONS,
321 lowest_kernel_version); 340 lowest_kernel_key_version,
341 lowest_kernel_version))
342 return LOAD_KERNEL_RECOVERY;
343 }
322 } 344 }
323 345
324 if (BOOT_MODE_RECOVERY != params->boot_mode) { 346 if (BOOT_MODE_RECOVERY != params->boot_mode) {
325 /* We can lock the TPM now, since we've decided which kernel we 347 /* We can lock the TPM now, since we've decided which kernel we
326 * like. If we don't find a good kernel, we leave the TPM 348 * like. If we don't find a good kernel, we leave the TPM
327 * unlocked so we can try again on the next boot device. If no 349 * unlocked so we can try again on the next boot device. If no
328 * kernels are good, we'll reboot to recovery mode, so it's ok to 350 * kernels are good, we'll reboot to recovery mode, so it's ok to
329 * leave the TPM unlocked in that case too. 351 * leave the TPM unlocked in that case too.
330 * 352 *
331 * If we're already in recovery mode, we need to leave PP unlocked, 353 * If we're already in recovery mode, we need to leave PP unlocked,
332 * so don't lock the kernel versions. */ 354 * so don't lock the kernel versions. */
333 LockKernelVersionsByLockingPP(); 355 if (0 != LockKernelVersionsByLockingPP())
356 return LOAD_KERNEL_RECOVERY;
334 } 357 }
335 358
336 /* Success! */ 359 /* Success! */
337 return LOAD_KERNEL_SUCCESS; 360 return LOAD_KERNEL_SUCCESS;
338 } 361 }
339 362
340 // Handle error cases 363 /* Handle error cases */
341 if (found_partition) 364 if (found_partition)
342 return LOAD_KERNEL_INVALID; 365 return LOAD_KERNEL_INVALID;
343 else 366 else
344 return LOAD_KERNEL_NOT_FOUND; 367 return LOAD_KERNEL_NOT_FOUND;
345 /* TODO: no error code for "internal error", but what would the firmware do
346 * with that anyway? So in the do-while(0) code above, the firmware just
347 * does 'break' to indicate an internal error... */
348 } 368 }
OLDNEW
« no previous file with comments | « vboot_firmware/include/rollback_index.h ('k') | vboot_firmware/lib/rollback_index.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698