diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | Makefile.rules | 19 | ||||
-rw-r--r-- | Makefile.toolchain | 3 | ||||
-rw-r--r-- | board/bds/build.mk | 1 | ||||
-rw-r--r-- | board/daisy/build.mk | 1 | ||||
-rw-r--r-- | board/link/build.mk | 1 | ||||
-rw-r--r-- | board/snow/build.mk | 1 | ||||
-rw-r--r-- | chip/lm4/build.mk | 1 | ||||
-rw-r--r-- | chip/stm32/build.mk | 1 | ||||
-rw-r--r-- | common/build.mk | 31 | ||||
-rw-r--r-- | common/fmap.c | 1 | ||||
-rw-r--r-- | common/uart_buffering.c | 5 | ||||
-rw-r--r-- | common/vboot.c | 147 | ||||
-rw-r--r-- | common/vboot_stub.c | 168 | ||||
-rw-r--r-- | core/cortex-m/build.mk | 1 | ||||
-rw-r--r-- | include/util.h | 8 | ||||
-rw-r--r-- | test/build.mk | 4 | ||||
-rw-r--r-- | util/build.mk | 1 |
18 files changed, 375 insertions, 22 deletions
@@ -38,6 +38,8 @@ include common/build.mk include test/build.mk include util/build.mk +includes+=$(includes-y) + objs_from_dir=$(foreach obj,$(2), $(out)/$(1)/$(obj)) # Get all sources to build @@ -47,6 +49,7 @@ all-y+=$(call objs_from_dir,board/$(BOARD),$(board-y)) all-y+=$(call objs_from_dir,private,$(private-y)) all-y+=$(call objs_from_dir,common,$(common-y)) all-y+=$(call objs_from_dir,test,$($(PROJECT)-y)) +all-y+=$(call objs_from_dir,vboot,$(vboot-y)) dirs=core/$(CORE) chip/$(CHIP) board/$(BOARD) private common test util include Makefile.rules diff --git a/Makefile.rules b/Makefile.rules index ea7a961777..5a94984813 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2011 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. @@ -13,6 +14,8 @@ host-utils := $(foreach u,$(host-util-bin),$(out)/util/$(u)) # Create output directories if necessary _dir_create := $(foreach d,$(dirs),$(shell [ -d $(out)/$(d) ] || \ mkdir -p $(out)/$(d))) +_dir_y_create := $(foreach d,$(dirs-y),$(shell [ -d $(out)/$(d) ] || \ + mkdir -p $(out)/$(d))) section = $(subst .,,$(suffix $(1))) section_is = $(subst .,,SECTION_IS_$(suffix $(1))) @@ -38,6 +41,13 @@ cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d $< -o $@ cmd_qemu = ./util/run_qemu_test --image=build/$(BOARD)/$*/$*.bin test/$*.py \ $(silent) cmd_version = ./util/getversion.sh > $@ +cmd_sign = vbutil_ec --sign $@ \ + --version 1 \ + --keyblock $(VBOOT_DEVKEYS)/ec.keyblock \ + --signprivate $(VBOOT_DEVKEYS)/ec_data_key.vbprivk \ + --signpubkey $(VBOOT_DEVKEYS)/ec_root_key.vbpubk \ + $(silent) +cmd_mv = mv $^ $@ .PHONY: all tests utils @@ -66,8 +76,12 @@ $(out)/firmware_image.lds: common/firmware_image.lds.S $(out)/%.lds: core/$(CORE)/ec.lds.S $(call quiet,lds,LDS ) -$(out)/%.bin: $(out)/%.obj +$(out)/%.bin: $(out)/%.bin.tmp + $(call quiet,mv,MV ) + +$(out)/%.bin.tmp: $(out)/%.obj $(call quiet,obj_to_bin,OBJCOPY) + $(if $(sign-y),$(call quiet,sign,SIGN ),) $(out)/%.obj: common/firmware_image.S $(out)/firmware_image.lds \ $(out)/%.RO.flat $(out)/%.A.flat $(out)/%.B.flat @@ -85,6 +99,9 @@ $(out)/%.elf: $(out)/%.lds $(objs) $(out)/%.o:%.c $(call quiet,c_to_o,CC ) +$(out)/vboot/%.o:$(VBOOT_SOURCE)/%.c + $(call quiet,c_to_o,CC ) + $(out)/%.o:%.S $(call quiet,c_to_o,AS ) diff --git a/Makefile.toolchain b/Makefile.toolchain index 1b55247ff5..537d9a2b82 100644 --- a/Makefile.toolchain +++ b/Makefile.toolchain @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. @@ -28,7 +29,7 @@ CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DTASKFILE=$(PROJECT).tasklist \ -DBOARD=$(BOARD) -DBOARD_$(BOARD) -DCORE=$(CORE) -DCHIP_$(CHIP) \ -DCHIP_VARIANT=$(CHIP_VARIANT) -DCHIP_VARIANT_$(CHIP_VARIANT) CPPFLAGS=$(CFLAGS_DEFINE) $(CFLAGS_INCLUDE) -CFLAGS=$(CPPFLAGS) $(CFLAGS_CPU) $(CFLAGS_DEBUG) $(CFLAGS_WARN) +CFLAGS=$(CPPFLAGS) $(CFLAGS_CPU) $(CFLAGS_DEBUG) $(CFLAGS_WARN) $(CFLAGS_y) BUILD_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN) HOST_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN) LDFLAGS=-nostdlib -X diff --git a/board/bds/build.mk b/board/bds/build.mk index b8e0572b53..d53bdde96c 100644 --- a/board/bds/build.mk +++ b/board/bds/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/board/daisy/build.mk b/board/daisy/build.mk index b09b1c7f4b..3fd1e94556 100644 --- a/board/daisy/build.mk +++ b/board/daisy/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/board/link/build.mk b/board/link/build.mk index 7ddc9b4f32..e22d4573f7 100644 --- a/board/link/build.mk +++ b/board/link/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/board/snow/build.mk b/board/snow/build.mk index 4732080d23..53d994e236 100644 --- a/board/snow/build.mk +++ b/board/snow/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk index 56bf793582..b93cc7816e 100644 --- a/chip/lm4/build.mk +++ b/chip/lm4/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index 4d296f186e..03877cf6fe 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/common/build.mk b/common/build.mk index 8c81d9866b..b5ecfa5a04 100644 --- a/common/build.mk +++ b/common/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. @@ -27,4 +28,32 @@ common-$(CONFIG_TASK_THERMAL)+=thermal.o thermal_commands.o common-$(CONFIG_TASK_X86POWER)+=x86_power.o common-$(CONFIG_TMP006)+=tmp006.o common-$(CONFIG_USB_CHARGE)+=usb_charge.o usb_charge_commands.o -common-$(CONFIG_VBOOT)+=vboot.o fmap.o + +# verified boot stuff +VBOOT_SOURCE?=/usr/src/vboot +VBOOT_DEVKEYS?=/usr/share/vboot/devkeys + +CFLAGS_$(CONFIG_VBOOT)+= -DCHROMEOS_ENVIRONMENT -DCHROMEOS_EC +# CFLAGS_$(CONFIG_VBOOT)+= -DVBOOT_DEBUG + +common-$(CONFIG_VBOOT)+= fmap.o vboot.o vboot_stub.o + +includes-$(CONFIG_VBOOT)+= \ + $(VBOOT_SOURCE)/include \ + $(VBOOT_SOURCE)/lib/include \ + $(VBOOT_SOURCE)/lib/cryptolib/include + +dirs-$(CONFIG_VBOOT)+= \ + vboot/lib vboot/lib/cryptolib + +vboot-$(CONFIG_VBOOT)+= \ + lib/vboot_common.o \ + lib/utility.o \ + lib/cryptolib/padding.o \ + lib/cryptolib/rsa_utility.o \ + lib/cryptolib/rsa.o \ + lib/cryptolib/sha_utility.o \ + lib/cryptolib/sha256.o \ + lib/stateful_util.o + +sign-$(CONFIG_VBOOT)+=sign_image diff --git a/common/fmap.c b/common/fmap.c index 3f7baceb93..40524c21ef 100644 --- a/common/fmap.c +++ b/common/fmap.c @@ -83,7 +83,6 @@ const struct _ec_fmap { .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, { - /* FIXME(wfrichar): GBB != FMAP. Use the right terms */ .area_name = "FMAP", .area_offset = (uint32_t)&ec_fmap, .area_size = sizeof(ec_fmap), diff --git a/common/uart_buffering.c b/common/uart_buffering.c index d83b34ea40..5848a30f1d 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -549,6 +549,11 @@ int uart_printf(const char *format, ...) va_end(args); return rv; } +/* For use when debugging verified boot. We could wrap it with a real function, + * but it's rarely needed and this doesn't add any extra code. We have to + * declare it here in order for this trick to work. */ +void VbExDebug(const char *format, ...) + __attribute__((weak, alias("uart_printf"))); void uart_flush_output(void) diff --git a/common/vboot.c b/common/vboot.c index 80750faa7f..31baad9d82 100644 --- a/common/vboot.c +++ b/common/vboot.c @@ -6,16 +6,84 @@ /* Verified boot module for Chrome EC */ #include "console.h" +#include "cryptolib.h" #include "gpio.h" #include "keyboard_scan.h" #include "system.h" +#include "timer.h" #include "util.h" #include "vboot.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_struct.h" +#include "watchdog.h" /* Console output macros */ #define CPUTS(outstr) cputs(CC_VBOOT, outstr) #define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args) +/****************************************************************************/ + +enum howgood { + IMAGE_IS_BAD, + IMAGE_IS_GOOD, + IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY, +}; + +static enum howgood good_image(uint8_t *key_data, + uint8_t *vblock_data, uint32_t vblock_size, + uint8_t *fv_data, uint32_t fv_size) { + VbPublicKey *sign_key; + VbKeyBlockHeader *key_block; + VbECPreambleHeader *preamble; + uint32_t now = 0; + RSAPublicKey *rsa; + + key_block = (VbKeyBlockHeader *)vblock_data; + sign_key = (VbPublicKey *)key_data; + + watchdog_reload(); + if (0 != KeyBlockVerify(key_block, vblock_size, sign_key, 0)) { + CPRINTF("[Error verifying key block]\n"); + return IMAGE_IS_BAD; + } + + now += key_block->key_block_size; + rsa = PublicKeyToRSA(&key_block->data_key); + if (!rsa) { + CPRINTF("[Error parsing data key]\n"); + return IMAGE_IS_BAD; + } + + watchdog_reload(); + preamble = (VbECPreambleHeader *)(vblock_data + now); + if (0 != VerifyECPreamble(preamble, vblock_size - now, rsa)) { + CPRINTF("[Error verifying preamble]\n"); + RSAPublicKeyFree(rsa); + return IMAGE_IS_BAD; + } + + if (preamble->flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { + CPRINTF("[Flags says USE_RO_NORMAL]\n"); + RSAPublicKeyFree(rsa); + return IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY; + } + + watchdog_reload(); + if (0 != EqualData(fv_data, fv_size, &preamble->body_digest, rsa)) { + CPRINTF("Error verifying firmware body]\n"); + RSAPublicKeyFree(rsa); + return IMAGE_IS_BAD; + } + + RSAPublicKeyFree(rsa); + + watchdog_reload(); + CPRINTF("[Verified!]\n"); + return IMAGE_IS_GOOD; +} + +/****************************************************************************/ /* Might I want to jump to one of the RW images? */ static int maybe_jump_to_other_image(void) @@ -68,27 +136,70 @@ int vboot_pre_init(void) return EC_SUCCESS; } - int vboot_init(void) { - /* nothing to do, so do nothing */ + enum howgood r; + timestamp_t ts1, ts2; + + CPRINTF("\n[--- %s() ---]\n", __func__); + if (!maybe_jump_to_other_image()) return EC_SUCCESS; - /* FIXME(wfrichar): placeholder for full verified boot implementation. - * TBD exactly how, but we may want to continue in RO firmware, jump - * directly to one of the RW firmwares, etc. */ - CPRINTF("[ROOT_KEY is at 0x%x, size 0x%x]\n", - CONFIG_VBOOT_ROOTKEY_OFF, CONFIG_VBOOT_ROOTKEY_SIZE); - CPRINTF("[FW_MAIN_A is at 0x%x, size 0x%x]\n", - CONFIG_FW_A_OFF, CONFIG_FW_A_SIZE); - CPRINTF("[VBLOCK_A is at 0x%x, size 0x%x]\n", - CONFIG_VBLOCK_A_OFF, CONFIG_VBLOCK_A_SIZE); - CPRINTF("[FW_MAIN_B is at 0x%x, size 0x%x]\n", - CONFIG_FW_B_OFF, CONFIG_FW_B_SIZE); - CPRINTF("[VBLOCK_B is at 0x%x, size 0x%x]\n", - CONFIG_VBLOCK_B_OFF, CONFIG_VBLOCK_B_SIZE); - - system_run_image_copy(SYSTEM_IMAGE_RW_A, 0); - return EC_SUCCESS; + CPRINTF("[Check image A...]\n"); + + ts1 = get_time(); + r = good_image((uint8_t *)CONFIG_VBOOT_ROOTKEY_OFF, + (uint8_t *)CONFIG_VBLOCK_A_OFF, CONFIG_VBLOCK_A_SIZE, + (uint8_t *)CONFIG_FW_A_OFF, CONFIG_FW_A_SIZE); + ts2 = get_time(); + + CPRINTF("[result=%d, elapsed time=%ld]\n", r, ts2.val - ts1.val); + + switch (r) { + case IMAGE_IS_GOOD: + CPRINTF("[Image A verified at %T]\n"); + system_run_image_copy(SYSTEM_IMAGE_RW_A, 0); + CPRINTF("[ERROR: Unable to jump to image A]\n"); + goto bad; + case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY: + CPRINTF("[Image A verified at %T]\n"); + CPRINTF("[Staying in RO mode]\n"); + return EC_SUCCESS; + default: + CPRINTF("[Image A is invalid]\n"); + } + +#ifdef CONFIG_NO_RW_B + CPRINTF("[No image B to check]\n"); +#else + CPRINTF("[Check image B...]\n"); + + ts1 = get_time(); + r = good_image((uint8_t *)CONFIG_VBOOT_ROOTKEY_OFF, + (uint8_t *)CONFIG_VBLOCK_B_OFF, CONFIG_VBLOCK_B_SIZE, + (uint8_t *)CONFIG_FW_B_OFF, CONFIG_FW_B_SIZE); + ts2 = get_time(); + + CPRINTF("[result=%d, elapsed time=%ld]\n", r, ts2.val - ts1.val); + + switch (r) { + case IMAGE_IS_GOOD: + CPRINTF("[Image B verified at %T]\n"); + system_run_image_copy(SYSTEM_IMAGE_RW_B, 0); + CPRINTF("[ERROR: Unable to jump to image B]\n"); + goto bad; + case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY: + CPRINTF("[Image B verified at %T]\n"); + CPRINTF("[Staying in RO mode]\n"); + return EC_SUCCESS; + default: + CPRINTF("[Image B is invalid]\n"); + } +#endif + +bad: + CPRINTF("[Staying in RO mode]\n"); + CPRINTF("[FIXME: How to trigger recovery mode?]\n"); + return EC_ERROR_UNKNOWN; } diff --git a/common/vboot_stub.c b/common/vboot_stub.c new file mode 100644 index 0000000000..b9b6bed691 --- /dev/null +++ b/common/vboot_stub.c @@ -0,0 +1,168 @@ +/* Copyright (c) 2012 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. + */ + +/* Functions needed by vboot library */ + +#define _STUB_IMPLEMENTATION_ +#include "console.h" +#include "shared_mem.h" +#include "util.h" +#include "utility.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_VBOOT, outstr) +#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args) + +#if 0 /* change this to debug memory usage */ +#define DPRINTF CPRINTF +#else +#define DPRINTF(...) +#endif + + +/****************************************************************************/ + +void *Memcpy(void *dest, const void *src, uint64_t n) +{ + return memcpy(dest, src, (size_t)n); +} + +void *Memset(void *d, const uint8_t c, uint64_t n) +{ + return memset(d, c, n); +} + +int Memcmp(const void *src1, const void *src2, size_t n) +{ + size_t i; + const uint8_t *a = src1; + const uint8_t *b = src2; + for (i = 0; i < n; i++) { + if (*a != *b) + return (*a < *b) ? -1 : 1; + a++; + b++; + } + + return 0; +} + +/****************************************************************************/ +/* The vboot_api library requires some dynamic memory, but we don't have + * malloc/free. Instead we have one chunk of shared RAM that we can gain + * exclusive access to for a time. We'll have to experiment with various + * algorithms to see what works best. This algorithm allocates and + * reuses blocks, but never actually frees anything until all memory has been + * reclaimed. */ + +/* Since we only need this stuff to boot, don't waste run-time .bss */ +static struct { + int bucket_size; /* total RAM available */ + uint8_t *out_base; /* malloc from here */ + int out_count; /* number of active mallocs */ + int out_size; /* high-water mark */ + + /* We have a limited number of active mallocs. We never free, but we + * do reuse slots. */ +#define MAX_SLOTS 8 + struct { + int in_use; /* is this slot active? */ + void *ptr; /* starts here */ + size_t size; /* how big */ + } slots[MAX_SLOTS]; +} *bucket; + + +void *VbExMalloc(size_t size) +{ + int i, j; + void *ptr = 0; + + if (!bucket) { + i = shared_mem_size(); + if (EC_SUCCESS != shared_mem_acquire(i, 1, (char **)&bucket)) { + CPRINTF("FAILED at %s:%d\n", __FILE__, __LINE__); + ASSERT(0); + } + Memset(bucket, 0, sizeof(*bucket)); + bucket->bucket_size = i; + bucket->out_base = (uint8_t *)(bucket + 1); + bucket->out_size = sizeof(*bucket); + DPRINTF("grab the bucket: at 0x%x, size 0x%x\n", + bucket, bucket->bucket_size); + } + + if (size % 8) { + int tmp = (size + 8) & ~0x7ULL; + DPRINTF(" %d -> %d\n", size, tmp); + size = tmp; + } + + for (i = 0; i < MAX_SLOTS; i++) { + if (!bucket->slots[i].in_use) { + + /* Found an empty one, but reuse the same size if one + * already exists. */ + for (j = i; j < MAX_SLOTS; j++) { + if (!bucket->slots[j].in_use && + size == bucket->slots[j].size) { + /* empty AND same size */ + bucket->slots[j].in_use = 1; + ptr = bucket->slots[j].ptr; + DPRINTF(" = %d (%d)\n", j, size); + goto out; + } + } + + /* no exact matches, must allocate a new chunk */ + ptr = bucket->out_base + bucket->out_size; + bucket->out_size += size; + + bucket->slots[i].in_use = 1; + bucket->slots[i].ptr = ptr; + bucket->slots[i].size = size; + DPRINTF(" + %d (%d)\n", i, size); + goto out; + } + } + + CPRINTF("FAILED: no empty slots (%d/%d)\n", i, MAX_SLOTS); + ASSERT(0); + +out: + bucket->out_count++; + if (bucket->out_size >= bucket->bucket_size) { + CPRINTF("FAILED: out of memory (%d/%d)\n", + bucket->out_size, bucket->bucket_size); + ASSERT(0); + } + + return ptr; +} + + +void VbExFree(void *ptr) +{ + int i; + + for (i = 0; i < MAX_SLOTS; i++) { + if (ptr == bucket->slots[i].ptr) { + bucket->slots[i].in_use = 0; + DPRINTF(" - %d (%d)\n", i, bucket->slots[i].size); + break; + } + } + if (MAX_SLOTS == i) { + CPRINTF("FAILED: can't find ptr %x!\n", ptr); + ASSERT(0); + } + + bucket->out_count--; + if (!bucket->out_count) { + DPRINTF("dump the bucket: max used = %d\n", bucket->out_size); + shared_mem_release(bucket); + bucket = 0; + } +} diff --git a/core/cortex-m/build.mk b/core/cortex-m/build.mk index 8f6225db76..5abd25ba08 100644 --- a/core/cortex-m/build.mk +++ b/core/cortex-m/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2012 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. diff --git a/include/util.h b/include/util.h index 6f8fe1c581..3fb0657061 100644 --- a/include/util.h +++ b/include/util.h @@ -32,10 +32,18 @@ /* Standard macros / definitions */ +#ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif +#ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef NULL #define NULL ((void *)0) +#endif /** * macros for integer division with various rounding variants diff --git a/test/build.mk b/test/build.mk index 7bc5731ac9..5cbbfbcd21 100644 --- a/test/build.mk +++ b/test/build.mk @@ -1,3 +1,7 @@ +# -*- makefile -*- +# Copyright (c) 2012 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. # # on-board test binaries build # diff --git a/util/build.mk b/util/build.mk index e8a930ed78..a3aa636b06 100644 --- a/util/build.mk +++ b/util/build.mk @@ -1,3 +1,4 @@ +# -*- makefile -*- # Copyright (c) 2011 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. |