summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--README34
-rw-r--r--arch/arm/cpu/armv7/s5p-common/timer.c2
-rw-r--r--arch/arm/dts/exynos5250.dtsi2
-rw-r--r--arch/arm/include/asm/arch-exynos/cpu.h10
-rw-r--r--arch/arm/lib/bootm.c27
-rw-r--r--arch/m68k/cpu/mcf5445x/speed.c10
-rw-r--r--arch/m68k/include/asm/m5235.h2
-rw-r--r--arch/m68k/lib/board.c4
-rw-r--r--arch/microblaze/lib/bootm.c4
-rw-r--r--arch/nios2/lib/bootm.c4
-rw-r--r--arch/openrisc/lib/bootm.c4
-rw-r--r--arch/sandbox/cpu/cpu.c2
-rw-r--r--arch/sandbox/cpu/os.c2
-rw-r--r--arch/x86/include/asm/global_data.h2
-rw-r--r--arch/x86/include/asm/msr.h3
-rw-r--r--arch/x86/include/asm/u-boot-x86.h2
-rw-r--r--arch/x86/lib/bootm.c2
-rw-r--r--arch/x86/lib/gcc.c4
-rw-r--r--arch/x86/lib/tsc_timer.c6
-rw-r--r--board/samsung/dts/exynos5250-snow.dts81
-rw-r--r--board/samsung/smdk5250/exynos5-dt.c45
-rw-r--r--common/Makefile2
-rw-r--r--common/board_f.c17
-rw-r--r--common/board_r.c11
-rw-r--r--common/bootstage.c26
-rw-r--r--common/cmd_bootm.c546
-rw-r--r--common/cmd_ide.c14
-rw-r--r--common/cmd_mem.c2
-rw-r--r--common/cmd_trace.c133
-rw-r--r--common/image-fdt.c13
-rw-r--r--common/image-fit.c83
-rw-r--r--common/image-sig.c422
-rw-r--r--common/image.c22
-rw-r--r--common/usb_storage.c8
-rw-r--r--config.mk12
-rw-r--r--doc/README.plan918
-rw-r--r--doc/README.trace361
-rw-r--r--doc/device-tree-bindings/input/cros-ec-keyb.txt79
-rw-r--r--doc/device-tree-bindings/misc/cros-ec.txt38
-rw-r--r--doc/mkimage.173
-rw-r--r--doc/uImage.FIT/sign-configs.its45
-rw-r--r--doc/uImage.FIT/sign-images.its42
-rw-r--r--doc/uImage.FIT/signature.txt382
-rw-r--r--doc/uImage.FIT/verified-boot.txt104
-rw-r--r--drivers/hwmon/lm63.c3
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/cros_ec_keyb.c261
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/cros_ec.c1304
-rw-r--r--drivers/misc/cros_ec_i2c.c199
-rw-r--r--drivers/misc/cros_ec_lpc.c283
-rw-r--r--drivers/misc/cros_ec_spi.c161
-rw-r--r--drivers/mmc/mmc.c17
-rw-r--r--drivers/mtd/cfi_flash.c7
-rw-r--r--drivers/serial/serial.c5
-rw-r--r--drivers/spi/exynos_spi.c22
-rw-r--r--drivers/usb/musb/musb_hcd.c3
-rw-r--r--drivers/usb/musb/musb_udc.c3
-rw-r--r--include/asm-generic/global_data.h3
-rw-r--r--include/common.h4
-rw-r--r--include/configs/coreboot.h7
-rw-r--r--include/configs/exynos5250-dt.h18
-rw-r--r--include/configs/sandbox.h15
-rw-r--r--include/cros_ec.h449
-rw-r--r--include/cros_ec_message.h44
-rw-r--r--include/ec_commands.h1440
-rw-r--r--include/fdtdec.h2
-rw-r--r--include/ide.h5
-rw-r--r--include/image.h182
-rw-r--r--include/libfdt.h64
-rw-r--r--include/part.h6
-rw-r--r--include/pci.h4
-rw-r--r--include/rsa.h108
-rw-r--r--include/spi.h16
-rw-r--r--include/trace.h125
-rw-r--r--include/vsprintf.h11
-rw-r--r--lib/Makefile1
-rw-r--r--lib/fdtdec.c2
-rw-r--r--lib/libfdt/fdt_wip.c129
-rw-r--r--lib/rsa/Makefile48
-rw-r--r--lib/rsa/rsa-sign.c460
-rw-r--r--lib/rsa/rsa-verify.c385
-rw-r--r--lib/trace.c379
-rw-r--r--lib/vsprintf.c16
-rwxr-xr-xtest/image/test-fit.py19
-rwxr-xr-xtest/trace/test-trace.sh89
-rw-r--r--test/vboot/.gitignore3
-rw-r--r--test/vboot/sandbox-kernel.dts7
-rw-r--r--test/vboot/sandbox-u-boot.dts7
-rw-r--r--test/vboot/sign-configs.its45
-rw-r--r--test/vboot/sign-images.its42
-rwxr-xr-xtest/vboot/vboot_test.sh126
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Makefile25
-rw-r--r--tools/fit_image.c44
-rw-r--r--tools/image-host.c527
-rw-r--r--tools/mkimage.c36
-rw-r--r--tools/mkimage.h4
-rw-r--r--tools/proftool.c611
100 files changed, 10036 insertions, 455 deletions
diff --git a/Makefile b/Makefile
index fdaddb9..fed766c 100644
--- a/Makefile
+++ b/Makefile
@@ -247,6 +247,7 @@ OBJS := $(addprefix $(obj),$(OBJS))
HAVE_VENDOR_COMMON_LIB = $(if $(wildcard board/$(VENDOR)/common/Makefile),y,n)
LIBS-y += lib/libgeneric.o
+LIBS-y += lib/rsa/librsa.o
LIBS-y += lib/lzma/liblzma.o
LIBS-y += lib/lzo/liblzo.o
LIBS-y += lib/zlib/libz.o
@@ -831,7 +832,8 @@ clean:
$(obj)tools/mk{smdk5250,}spl \
$(obj)tools/mxsboot \
$(obj)tools/ncb $(obj)tools/ubsha1 \
- $(obj)tools/kernel-doc/docproc
+ $(obj)tools/kernel-doc/docproc \
+ $(obj)tools/proftool
@rm -f $(obj)board/cray/L1/{bootscript.c,bootscript.image} \
$(obj)board/matrix_vision/*/bootscript.img \
$(obj)board/voiceblue/eeprom \
diff --git a/README b/README
index 137e8cb..5c343da 100644
--- a/README
+++ b/README
@@ -854,7 +854,7 @@ The following options need to be configured:
CONFIG_CMD_FDOS * Dos diskette Support
CONFIG_CMD_FLASH flinfo, erase, protect
CONFIG_CMD_FPGA FPGA device initialization support
- CONFIG_CMD_FUSE Device fuse support
+ CONFIG_CMD_FUSE * Device fuse support
CONFIG_CMD_GETTIME * Get time since boot
CONFIG_CMD_GO * the 'go' command (exec code)
CONFIG_CMD_GREPENV * search environment
@@ -864,7 +864,7 @@ The following options need to be configured:
CONFIG_CMD_IDE * IDE harddisk support
CONFIG_CMD_IMI iminfo
CONFIG_CMD_IMLS List all images found in NOR flash
- CONFIG_CMD_IMLS_NAND List all images found in NAND flash
+ CONFIG_CMD_IMLS_NAND * List all images found in NAND flash
CONFIG_CMD_IMMAP * IMMR dump support
CONFIG_CMD_IMPORTENV * import an environment
CONFIG_CMD_INI * import data from an ini file into the env
@@ -872,23 +872,24 @@ The following options need to be configured:
CONFIG_CMD_ITEST Integer/string test of 2 values
CONFIG_CMD_JFFS2 * JFFS2 Support
CONFIG_CMD_KGDB * kgdb
- CONFIG_CMD_LDRINFO ldrinfo (display Blackfin loader)
+ CONFIG_CMD_LDRINFO * ldrinfo (display Blackfin loader)
CONFIG_CMD_LINK_LOCAL * link-local IP address auto-configuration
(169.254.*.*)
CONFIG_CMD_LOADB loadb
CONFIG_CMD_LOADS loads
- CONFIG_CMD_MD5SUM print md5 message digest
+ CONFIG_CMD_MD5SUM * print md5 message digest
(requires CONFIG_CMD_MEMORY and CONFIG_MD5)
CONFIG_CMD_MEMINFO * Display detailed memory information
CONFIG_CMD_MEMORY md, mm, nm, mw, cp, cmp, crc, base,
loop, loopw
- CONFIG_CMD_MEMTEST mtest
+ CONFIG_CMD_MEMTEST * mtest
CONFIG_CMD_MISC Misc functions like sleep etc
CONFIG_CMD_MMC * MMC memory mapped support
CONFIG_CMD_MII * MII utility commands
CONFIG_CMD_MTDPARTS * MTD partition support
CONFIG_CMD_NAND * NAND support
CONFIG_CMD_NET bootp, tftpboot, rarpboot
+ CONFIG_CMD_NFS NFS support
CONFIG_CMD_PCA953X * PCA953x I2C gpio commands
CONFIG_CMD_PCA953X_INFO * PCA953x I2C gpio info command
CONFIG_CMD_PCI * pciinfo
@@ -907,7 +908,7 @@ The following options need to be configured:
CONFIG_CMD_SETGETDCR Support for DCR Register access
(4xx only)
CONFIG_CMD_SF * Read/write/erase SPI NOR flash
- CONFIG_CMD_SHA1SUM print sha1 memory digest
+ CONFIG_CMD_SHA1SUM * print sha1 memory digest
(requires CONFIG_CMD_MEMORY)
CONFIG_CMD_SOFTSWITCH * Soft switch setting command for BF60x
CONFIG_CMD_SOURCE "source" command Support
@@ -919,6 +920,7 @@ The following options need to be configured:
CONFIG_CMD_USB * USB support
CONFIG_CMD_CDP * Cisco Discover Protocol support
CONFIG_CMD_MFSL * Microblaze FSL support
+ CONFIG_CMD_XIMG Load part of Multi Image
EXAMPLE: If you want all functions except of network
@@ -1443,6 +1445,11 @@ CBFS (Coreboot Filesystem) support
Export function i8042_kbd_init, i8042_tstc and i8042_getc
for cfb_console. Supports cursor blinking.
+ CONFIG_CROS_EC_KEYB
+ Enables a Chrome OS keyboard using the CROS_EC interface.
+ This uses CROS_EC to communicate with a second microcontroller
+ which provides key scans on request.
+
- Video support:
CONFIG_VIDEO
@@ -2576,6 +2583,16 @@ CBFS (Coreboot Filesystem) support
Note: There is also a sha1sum command, which should perhaps
be deprecated in favour of 'hash sha1'.
+- Signing support:
+ CONFIG_RSA
+
+ This enables the RSA algorithm used for FIT image verification
+ in U-Boot. See doc/uImage/signature for more information.
+
+ The signing part is build into mkimage regardless of this
+ option.
+
+
- Show boot progress:
CONFIG_SHOW_BOOT_PROGRESS
@@ -2800,6 +2817,11 @@ FIT uImage format:
most specific compatibility entry of U-Boot's fdt's root node.
The order of entries in the configuration's fdt is ignored.
+ CONFIG_FIT_SIGNATURE
+ This option enables signature verification of FIT uImages,
+ using a hash signed and verified using RSA. See
+ doc/uImage.FIT/signature.txt for more details.
+
- Standalone program support:
CONFIG_STANDALONE_LOAD_ADDR
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c
index 4adfaae..637593c 100644
--- a/arch/arm/cpu/armv7/s5p-common/timer.c
+++ b/arch/arm/cpu/armv7/s5p-common/timer.c
@@ -95,7 +95,7 @@ unsigned long get_timer(unsigned long base)
return time_ms - base;
}
-unsigned long timer_get_us(void)
+unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
{
static unsigned long base_time_us;
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index cee4fe8..2d6dfff 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -202,4 +202,6 @@
interrupts = <0 78 0>;
};
+ gpio: gpio {
+ };
};
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
index 36b98c8..1ff7642 100644
--- a/arch/arm/include/asm/arch-exynos/cpu.h
+++ b/arch/arm/include/asm/arch-exynos/cpu.h
@@ -178,7 +178,7 @@ static inline char *s5p_get_cpu_name(void)
}
#define IS_SAMSUNG_TYPE(type, id) \
-static inline int cpu_is_##type(void) \
+static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \
{ \
return (s5p_cpu_id >> 12) == id; \
}
@@ -187,7 +187,8 @@ IS_SAMSUNG_TYPE(exynos4, 0x4)
IS_SAMSUNG_TYPE(exynos5, 0x5)
#define IS_EXYNOS_TYPE(type, id) \
-static inline int proid_is_##type(void) \
+static inline int __attribute__((no_instrument_function)) \
+ proid_is_##type(void) \
{ \
return s5p_cpu_id == id; \
}
@@ -197,9 +198,10 @@ IS_EXYNOS_TYPE(exynos4412, 0x4412)
IS_EXYNOS_TYPE(exynos5250, 0x5250)
#define SAMSUNG_BASE(device, base) \
-static inline unsigned int samsung_get_base_##device(void) \
+static inline unsigned int __attribute__((no_instrument_function)) \
+ samsung_get_base_##device(void) \
{ \
- if (cpu_is_exynos4()) { \
+ if (cpu_is_exynos4()) { \
if (proid_is_exynos4412()) \
return EXYNOS4X12_##base; \
return EXYNOS4_##base; \
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 1b6e0ac..b22fbc9 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -68,12 +68,19 @@ void arch_lmb_reserve(struct lmb *lmb)
gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);
}
-static void announce_and_cleanup(void)
+/**
+ * announce_and_cleanup() - Print message and prepare for kernel boot
+ *
+ * @fake: non-zero to do everything except actually boot
+ */
+static void announce_and_cleanup(int fake)
{
- printf("\nStarting kernel ...\n\n");
+ printf("\nStarting kernel ...%s\n\n", fake ?
+ "(fake run for tracing)" : "");
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
#ifdef CONFIG_BOOTSTAGE_FDT
- bootstage_fdt_add_report();
+ if (flag == BOOTM_STATE_OS_FAKE_GO)
+ bootstage_fdt_add_report();
#endif
#ifdef CONFIG_BOOTSTAGE_REPORT
bootstage_report();
@@ -225,12 +232,13 @@ static void boot_prep_linux(bootm_headers_t *images)
}
/* Subcommand: GO */
-static void boot_jump_linux(bootm_headers_t *images)
+static void boot_jump_linux(bootm_headers_t *images, int flag)
{
unsigned long machid = gd->bd->bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
+ int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(int, int, uint))images->ep;
@@ -243,14 +251,15 @@ static void boot_jump_linux(bootm_headers_t *images)
debug("## Transferring control to Linux (at address %08lx)" \
"...\n", (ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
- announce_and_cleanup();
+ announce_and_cleanup(fake);
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
r2 = (unsigned long)images->ft_addr;
else
r2 = gd->bd->bi_boot_params;
- kernel_entry(0, machid, r2);
+ if (!fake)
+ kernel_entry(0, machid, r2);
}
/* Main Entry point for arm bootm implementation
@@ -270,13 +279,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
return 0;
}
- if (flag & BOOTM_STATE_OS_GO) {
- boot_jump_linux(images);
+ if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+ boot_jump_linux(images, flag);
return 0;
}
boot_prep_linux(images);
- boot_jump_linux(images);
+ boot_jump_linux(images, flag);
return 0;
}
diff --git a/arch/m68k/cpu/mcf5445x/speed.c b/arch/m68k/cpu/mcf5445x/speed.c
index aa73e1f..0276d4d 100644
--- a/arch/m68k/cpu/mcf5445x/speed.c
+++ b/arch/m68k/cpu/mcf5445x/speed.c
@@ -122,17 +122,17 @@ void setup_5441x_clocks(void)
vco = ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) *
CONFIG_SYS_INPUT_CLKSRC;
- gd->vco_clk = vco;
+ gd->arch.vco_clk = vco;
- gd->inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
+ gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */
pdr = in_be32(&pll->pdr);
temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1;
gd->cpu_clk = vco / temp; /* cpu clock */
- gd->flb_clk = vco / temp; /* FlexBus clock */
- gd->flb_clk >>= 1;
+ gd->arch.flb_clk = vco / temp; /* FlexBus clock */
+ gd->arch.flb_clk >>= 1;
if (in_be16(ccm->misccr2) & 2) /* fsys/4 */
- gd->flb_clk >>= 1;
+ gd->arch.flb_clk >>= 1;
temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1;
gd->bus_clk = vco / temp; /* bus clock */
diff --git a/arch/m68k/include/asm/m5235.h b/arch/m68k/include/asm/m5235.h
index 71a40d3..a573f1c 100644
--- a/arch/m68k/include/asm/m5235.h
+++ b/arch/m68k/include/asm/m5235.h
@@ -134,7 +134,7 @@
#define SDRAMC_DCR_RC(x) (((x)&0xFF)<<8)
/* Bit definitions and macros for SDRAMC_DARCn */
-#define SDRAMC_DARCn_BA(x) (((x)&0xFFFC)<<18)
+#define SDRAMC_DARCn_BA(x) ((x)&0xFFFC0000)
#define SDRAMC_DARCn_RE (0x00008000)
#define SDRAMC_DARCn_CASL_MASK (0x00003000)
#define SDRAMC_DARCn_CASL_C0 (0x00000000)
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index b2e3068..efc9fcc 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -403,14 +403,14 @@ void board_init_r (gd_t *id, ulong dest_addr)
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
- debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
-
WATCHDOG_RESET ();
gd->reloc_off = dest_addr - CONFIG_SYS_MONITOR_BASE;
serial_initialize();
+ debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
+
monitor_flash_len = (ulong)&__init_end - dest_addr;
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c
index 3842709..b328f94 100644
--- a/arch/microblaze/lib/bootm.c
+++ b/arch/microblaze/lib/bootm.c
@@ -62,8 +62,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
- if (!of_flat_tree && argc > 3)
- of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16);
+ if (!of_flat_tree && argc > 1)
+ of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);
/* fixup the initrd now that we know where it should be */
if (images->rd_start && images->rd_end && of_flat_tree)
diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c
index f32be52..114e146 100644
--- a/arch/nios2/lib/bootm.c
+++ b/arch/nios2/lib/bootm.c
@@ -40,8 +40,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
if (images->ft_len)
of_flat_tree = images->ft_addr;
#endif
- if (!of_flat_tree && argc > 3)
- of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16);
+ if (!of_flat_tree && argc > 1)
+ of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);
if (of_flat_tree)
initrd_end = (ulong)of_flat_tree;
diff --git a/arch/openrisc/lib/bootm.c b/arch/openrisc/lib/bootm.c
index 2c5d9ae..7f716b8 100644
--- a/arch/openrisc/lib/bootm.c
+++ b/arch/openrisc/lib/bootm.c
@@ -63,8 +63,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
show_boot_progress(15);
- if (!of_flat_tree && argc > 3)
- of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16);
+ if (!of_flat_tree && argc > 1)
+ of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);
#ifdef DEBUG
printf("## Transferring control to Linux (at address 0x%08lx) " \
"ramdisk 0x%08lx, FDT 0x%08lx...\n",
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index dd8d495..e9385de 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -37,7 +37,7 @@ void __udelay(unsigned long usec)
os_usleep(usec);
}
-unsigned long timer_get_us(void)
+unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
{
return os_get_nsec() / 1000;
}
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index d075407..541e450 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -152,7 +152,7 @@ void os_usleep(unsigned long usec)
usleep(usec);
}
-u64 os_get_nsec(void)
+u64 __attribute__((no_instrument_function)) os_get_nsec(void)
{
#if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK)
struct timespec tp;
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 4fdb080..9a2056a 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -40,7 +40,7 @@ struct arch_global_data {
#include <asm-generic/global_data.h>
#ifndef __ASSEMBLY__
-static inline gd_t *get_fs_gd_ptr(void)
+static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)
{
gd_t *gd_ptr;
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 6030633..b459a63 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -85,7 +85,8 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
#define EAX_EDX_RET(val, low, high) "=A" (val)
#endif
-static inline unsigned long long native_read_msr(unsigned int msr)
+static inline __attribute__((no_instrument_function))
+ unsigned long long native_read_msr(unsigned int msr)
{
DECLARE_ARGS(val, low, high);
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 22e0934..709dc84 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -64,7 +64,7 @@ void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
void board_init_f_r(void) __attribute__ ((noreturn));
/* Read the time stamp counter */
-static inline uint64_t rdtsc(void)
+static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
{
uint32_t high, low;
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 2520228..0d3250c 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -63,6 +63,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
}
#if defined(CONFIG_FIT)
} else if (images->fit_uname_os) {
+ int ret;
+
ret = fit_image_get_data(images->fit_hdr_os,
images->fit_noffset_os, &data, &len);
if (ret) {
diff --git a/arch/x86/lib/gcc.c b/arch/x86/lib/gcc.c
index 4043431..497ad75 100644
--- a/arch/x86/lib/gcc.c
+++ b/arch/x86/lib/gcc.c
@@ -28,7 +28,9 @@
#define WRAP_LIBGCC_CALL(type, name) \
type __normal_##name(type a, type b) __attribute__((regparm(0))); \
type __wrap_##name(type a, type b); \
- type __wrap_##name(type a, type b) { return __normal_##name(a, b); }
+ type __attribute__((no_instrument_function)) \
+ __wrap_##name(type a, type b) \
+ { return __normal_##name(a, b); }
WRAP_LIBGCC_CALL(long long, __divdi3)
WRAP_LIBGCC_CALL(unsigned long long, __udivdi3)
diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
index c509801..0688973 100644
--- a/arch/x86/lib/tsc_timer.c
+++ b/arch/x86/lib/tsc_timer.c
@@ -37,7 +37,7 @@ void timer_set_base(u64 base)
* restart. This yields a free running counter guaranteed to take almost 6
* years to wrap around even at 100GHz clock rate.
*/
-u64 get_ticks(void)
+u64 __attribute__((no_instrument_function)) get_ticks(void)
{
u64 now_tick = rdtsc();
@@ -50,7 +50,7 @@ u64 get_ticks(void)
#define PLATFORM_INFO_MSR 0xce
/* Get the speed of the TSC timer in MHz */
-unsigned long get_tbclk_mhz(void)
+unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
{
u32 ratio;
u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
@@ -75,7 +75,7 @@ ulong get_timer(ulong base)
return get_ms_timer() - base;
}
-ulong timer_get_us(void)
+ulong __attribute__((no_instrument_function)) timer_get_us(void)
{
return get_ticks() / get_tbclk_mhz();
}
diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts
index 24658c1..d2ccc66 100644
--- a/board/samsung/dts/exynos5250-snow.dts
+++ b/board/samsung/dts/exynos5250-snow.dts
@@ -32,6 +32,33 @@
spi4 = "/spi@131b0000";
};
+ i2c4: i2c@12ca0000 {
+ cros-ec@1e {
+ reg = <0x1e>;
+ compatible = "google,cros-ec";
+ i2c-max-frequency = <100000>;
+ ec-interrupt = <&gpio 782 1>;
+ };
+
+ power-regulator@48 {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+ };
+ };
+
+ spi@131b0000 {
+ spi-max-frequency = <1000000>;
+ spi-deactivate-delay = <100>;
+ cros-ec@0 {
+ reg = <0>;
+ compatible = "google,cros-ec";
+ spi-max-frequency = <5000000>;
+ ec-interrupt = <&gpio 782 1>;
+ optimise-flash-write;
+ status = "disabled";
+ };
+ };
+
sound@12d60000 {
samsung,i2s-epll-clock-frequency = <192000000>;
samsung,i2s-sampling-rate = <48000>;
@@ -69,4 +96,58 @@
samsung,dc-value = <25>;
};
+ cros-ec-keyb {
+ compatible = "google,cros-ec-keyb";
+ google,key-rows = <8>;
+ google,key-columns = <13>;
+ google,repeat-delay-ms = <240>;
+ google,repeat-rate-ms = <30>;
+ google,ghost-filter;
+ /*
+ * Keymap entries take the form of 0xRRCCKKKK where
+ * RR=Row CC=Column KKKK=Key Code
+ * The values below are for a US keyboard layout and
+ * are taken from the Linux driver. Note that the
+ * 102ND key is not used for US keyboards.
+ */
+ linux,keymap = <
+ /* CAPSLCK F1 B F10 */
+ 0x0001003a 0x0002003b 0x00030030 0x00040044
+ /* N = R_ALT ESC */
+ 0x00060031 0x0008000d 0x000a0064 0x01010001
+ /* F4 G F7 H */
+ 0x0102003e 0x01030022 0x01040041 0x01060023
+ /* ' F9 BKSPACE L_CTRL */
+ 0x01080028 0x01090043 0x010b000e 0x0200001d
+ /* TAB F3 T F6 */
+ 0x0201000f 0x0202003d 0x02030014 0x02040040
+ /* ] Y 102ND [ */
+ 0x0205001b 0x02060015 0x02070056 0x0208001a
+ /* F8 GRAVE F2 5 */
+ 0x02090042 0x03010029 0x0302003c 0x03030006
+ /* F5 6 - \ */
+ 0x0304003f 0x03060007 0x0308000c 0x030b002b
+ /* R_CTRL A D F */
+ 0x04000061 0x0401001e 0x04020020 0x04030021
+ /* S K J ; */
+ 0x0404001f 0x04050025 0x04060024 0x04080027
+ /* L ENTER Z C */
+ 0x04090026 0x040b001c 0x0501002c 0x0502002e
+ /* V X , M */
+ 0x0503002f 0x0504002d 0x05050033 0x05060032
+ /* L_SHIFT / . SPACE */
+ 0x0507002a 0x05080035 0x05090034 0x050B0039
+ /* 1 3 4 2 */
+ 0x06010002 0x06020004 0x06030005 0x06040003
+ /* 8 7 0 9 */
+ 0x06050009 0x06060008 0x0608000b 0x0609000a
+ /* L_ALT DOWN RIGHT Q */
+ 0x060a0038 0x060b006c 0x060c006a 0x07010010
+ /* E R W I */
+ 0x07020012 0x07030013 0x07040011 0x07050017
+ /* U R_SHIFT P O */
+ 0x07060016 0x07070036 0x07080019 0x07090018
+ /* UP LEFT */
+ 0x070b0067 0x070c0069>;
+ };
};
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c
index 8131505..aacf43e 100644
--- a/board/samsung/smdk5250/exynos5-dt.c
+++ b/board/samsung/smdk5250/exynos5-dt.c
@@ -21,6 +21,7 @@
*/
#include <common.h>
+#include <cros_ec.h>
#include <fdtdec.h>
#include <asm/io.h>
#include <errno.h>
@@ -69,6 +70,13 @@ static void boot_temp_check(void)
}
#endif
+struct local_info {
+ struct cros_ec_dev *cros_ec_dev; /* Pointer to cros_ec device */
+ int cros_ec_err; /* Error for cros_ec, 0 if ok */
+};
+
+static struct local_info local;
+
#ifdef CONFIG_USB_EHCI_EXYNOS
int board_usb_vbus_init(void)
{
@@ -97,6 +105,20 @@ static void board_enable_audio_codec(void)
}
#endif
+struct cros_ec_dev *board_get_cros_ec_dev(void)
+{
+ return local.cros_ec_dev;
+}
+
+static int board_init_cros_ec_devices(const void *blob)
+{
+ local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev);
+ if (local.cros_ec_err)
+ return -1; /* Will report in board_late_init() */
+
+ return 0;
+}
+
int board_init(void)
{
gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL);
@@ -112,6 +134,10 @@ int board_init(void)
#ifdef CONFIG_EXYNOS_SPI
spi_init();
#endif
+
+ if (board_init_cros_ec_devices(gd->fdt_blob))
+ return -1;
+
#ifdef CONFIG_USB_EHCI_EXYNOS
board_usb_vbus_init();
#endif
@@ -421,3 +447,22 @@ void exynos_set_dp_phy(unsigned int onoff)
set_dp_phy_ctrl(onoff);
}
#endif
+
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+ stdio_print_current_devices();
+
+ if (local.cros_ec_err) {
+ /* Force console on */
+ gd->flags &= ~GD_FLG_SILENT;
+
+ printf("cros-ec communications failure %d\n",
+ local.cros_ec_err);
+ puts("\nPlease reset with Power+Refresh\n\n");
+ panic("Cannot init cros-ec device");
+ return -1;
+ }
+ return 0;
+}
+#endif
diff --git a/common/Makefile b/common/Makefile
index 3581603..48791b7 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -169,6 +169,7 @@ COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o
COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o
COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
COBJS-$(CONFIG_CMD_TIME) += cmd_time.o
+COBJS-$(CONFIG_CMD_TRACE) += cmd_trace.o
COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o
COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o
COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o
@@ -242,6 +243,7 @@ COBJS-y += dlmalloc.o
COBJS-y += image.o
COBJS-$(CONFIG_OF_LIBFDT) += image-fdt.o
COBJS-$(CONFIG_FIT) += image-fit.o
+COBJS-$(CONFIG_FIT_SIGNATURE) += image-sig.o
COBJS-y += memsize.o
COBJS-y += stdio.o
diff --git a/common/board_f.c b/common/board_f.c
index 8efdb63..ab4242a 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -53,6 +53,7 @@
#include <os.h>
#include <post.h>
#include <spi.h>
+#include <trace.h>
#include <watchdog.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -500,6 +501,18 @@ static int reserve_lcd(void)
}
#endif /* CONFIG_LCD */
+static int reserve_trace(void)
+{
+#ifdef CONFIG_TRACE
+ gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
+ gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
+ debug("Reserving %dk for trace data at: %08lx\n",
+ CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
+#endif
+
+ return 0;
+}
+
#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \
&& !defined(CONFIG_ARM) && !defined(CONFIG_X86)
static int reserve_video(void)
@@ -818,8 +831,9 @@ static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
setup_ram_buf,
#endif
- setup_fdt,
setup_mon_len,
+ setup_fdt,
+ trace_early_init,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
/* TODO: can this go into arch_cpu_init()? */
probecpu,
@@ -963,6 +977,7 @@ static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_LCD
reserve_lcd,
#endif
+ reserve_trace,
/* TODO: Why the dependency on CONFIG_8xx? */
#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \
&& !defined(CONFIG_ARM) && !defined(CONFIG_X86)
diff --git a/common/board_r.c b/common/board_r.c
index f5649c9..f7a036e 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -58,6 +58,7 @@
#include <serial.h>
#include <spi.h>
#include <stdio_dev.h>
+#include <trace.h>
#include <watchdog.h>
#ifdef CONFIG_ADDR_MAP
#include <asm/mmu.h>
@@ -106,6 +107,15 @@ static int initr_secondary_cpu(void)
return 0;
}
+static int initr_trace(void)
+{
+#ifdef CONFIG_TRACE
+ trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE);
+#endif
+
+ return 0;
+}
+
static int initr_reloc(void)
{
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
@@ -711,6 +721,7 @@ static int run_main_loop(void)
* TODO: perhaps reset the watchdog in the initcall function after each call?
*/
init_fnc_t init_sequence_r[] = {
+ initr_trace,
initr_reloc,
/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
diff --git a/common/bootstage.c b/common/bootstage.c
index c5c6996..94a32a9 100644
--- a/common/bootstage.c
+++ b/common/bootstage.c
@@ -49,6 +49,7 @@ static int next_id = BOOTSTAGE_ID_USER;
enum {
BOOTSTAGE_VERSION = 0,
BOOTSTAGE_MAGIC = 0xb00757a3,
+ BOOTSTAGE_DIGITS = 9,
};
struct bootstage_hdr {
@@ -165,21 +166,6 @@ uint32_t bootstage_accum(enum bootstage_id id)
return duration;
}
-static void print_time(unsigned long us_time)
-{
- char str[15], *s;
- int grab = 3;
-
- /* We don't seem to have %'d in U-Boot */
- sprintf(str, "%12lu", us_time);
- for (s = str + 3; *s; s += grab) {
- if (s != str + 3)
- putc(s[-1] != ' ' ? ',' : ' ');
- printf("%.*s", grab, s);
- grab = 3;
- }
-}
-
/**
* Get a record name as a printable string
*
@@ -208,10 +194,10 @@ static uint32_t print_time_record(enum bootstage_id id,
if (prev == -1U) {
printf("%11s", "");
- print_time(rec->time_us);
+ print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
} else {
- print_time(rec->time_us);
- print_time(rec->time_us - prev);
+ print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
+ print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);
}
printf(" %s\n", get_record_name(buf, sizeof(buf), rec));
@@ -445,9 +431,9 @@ int bootstage_unstash(void *base, int size)
}
if (hdr->count * sizeof(*rec) > hdr->size) {
- debug("%s: Bootstage has %d records needing %d bytes, but "
+ debug("%s: Bootstage has %d records needing %lu bytes, but "
"only %d bytes is available\n", __func__, hdr->count,
- hdr->count * sizeof(*rec), hdr->size);
+ (ulong)hdr->count * sizeof(*rec), hdr->size);
return -1;
}
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index e452fca..ba0bcd4 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -104,9 +104,18 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
* - verified image architecture (PPC) and type (KERNEL or MULTI),
* - loaded (first part of) image to header load address,
* - disabled interrupts.
+ *
+ * @flag: Flags indicating what to do (BOOTM_STATE_...)
+ * @argc: Number of arguments. Note that the arguments are shifted down
+ * so that 0 is the first argument not processed by U-Boot, and
+ * argc is adjusted accordingly. This avoids confusion as to how
+ * many arguments are available for the OS.
+ * @images: Pointers to os/initrd/fdt
+ * @return 1 on error. On success the OS boots so this function does
+ * not return.
*/
typedef int boot_os_fn(int flag, int argc, char * const argv[],
- bootm_headers_t *images); /* pointers to os/initrd/fdt */
+ bootm_headers_t *images);
#ifdef CONFIG_BOOTM_LINUX
extern boot_os_fn do_bootm_linux;
@@ -199,15 +208,21 @@ static inline void boot_start_lmb(bootm_headers_t *images) { }
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- const void *os_hdr;
- int ret;
-
memset((void *)&images, 0, sizeof(images));
images.verify = getenv_yesno("verify");
boot_start_lmb(&images);
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
+ images.state = BOOTM_STATE_START;
+
+ return 0;
+}
+
+static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ const void *os_hdr;
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -270,6 +285,8 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
images.ep = image_get_ep(&images.legacy_hdr_os_copy);
#if defined(CONFIG_FIT)
} else if (images.fit_uname_os) {
+ int ret;
+
ret = fit_image_get_entry(images.fit_hdr_os,
images.fit_noffset_os, &images.ep);
if (ret) {
@@ -287,6 +304,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
images.ep += images.os.load;
}
+ images.os.start = (ulong)os_hdr;
+
+ return 0;
+}
+
+static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ int ret;
+
if (((images.os.type == IH_TYPE_KERNEL) ||
(images.os.type == IH_TYPE_KERNEL_NOLOAD) ||
(images.os.type == IH_TYPE_MULTI)) &&
@@ -312,9 +339,6 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
#endif
}
- images.os.start = (ulong)os_hdr;
- images.state = BOOTM_STATE_START;
-
return 0;
}
@@ -446,7 +470,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
return 0;
}
-static int bootm_start_standalone(ulong iflag, int argc, char * const argv[])
+static int bootm_start_standalone(int argc, char * const argv[])
{
char *s;
int (*appl)(int, char * const []);
@@ -457,7 +481,7 @@ static int bootm_start_standalone(ulong iflag, int argc, char * const argv[])
return 0;
}
appl = (int (*)(int, char * const []))(ulong)ntohl(images.ep);
- (*appl)(argc-1, &argv[1]);
+ (*appl)(argc, argv);
return 0;
}
@@ -475,108 +499,225 @@ static cmd_tbl_t cmd_bootm_sub[] = {
U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
+ U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),
U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
};
+static int boot_selected_os(int argc, char * const argv[], int state,
+ bootm_headers_t *images, boot_os_fn *boot_fn, ulong *iflag)
+{
+ if (images->os.type == IH_TYPE_STANDALONE) {
+ /* This may return when 'autostart' is 'no' */
+ bootm_start_standalone(argc, argv);
+ return 0;
+ }
+ /*
+ * We have reached the point of no return: we are going to
+ * overwrite all exception vector code, so we cannot easily
+ * recover from any failures any more...
+ */
+ *iflag = disable_interrupts();
+#ifdef CONFIG_NETCONSOLE
+ /* Stop the ethernet stack if NetConsole could have left it up */
+ eth_halt();
+#endif
+
+#if defined(CONFIG_CMD_USB)
+ /*
+ * turn off USB to prevent the host controller from writing to the
+ * SDRAM while Linux is booting. This could happen (at least for OHCI
+ * controller), because the HCCA (Host Controller Communication Area)
+ * lies within the SDRAM and the host controller writes continously to
+ * this area (as busmaster!). The HccaFrameNumber is for example
+ * updated every 1 ms within the HCCA structure in SDRAM! For more
+ * details see the OpenHCI specification.
+ */
+ usb_stop();
+#endif
+#ifdef CONFIG_SILENT_CONSOLE
+ if (images->os.os == IH_OS_LINUX)
+ fixup_silent_linux();
+#endif
+ arch_preboot_os();
+ boot_fn(state, argc, argv, images);
+ if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
+ return 0;
+ bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
+#ifdef DEBUG
+ puts("\n## Control returned to monitor - resetting...\n");
+#endif
+ return BOOTM_ERR_RESET;
+}
+
+/**
+ * Execute selected states of the bootm command.
+ *
+ * Note the arguments to this state must be the first argument, Any 'bootm'
+ * or sub-command arguments must have already been taken.
+ *
+ * Note that if states contains more than one flag it MUST contain
+ * BOOTM_STATE_START, since this handles and consumes the command line args.
+ *
+ * @param cmdtp Pointer to bootm command table entry
+ * @param flag Command flags (CMD_FLAG_...)
+ * @param argc Number of subcommand arguments (0 = no arguments)
+ * @param argv Arguments
+ * @param states Mask containing states to run (BOOTM_STATE_...)
+ * @param images Image header information
+ * @param boot_progress 1 to show boot progress, 0 to not do this
+ * @return 0 if ok, something else on error. Some errors will cause this
+ * function to perform a reboot! If states contains BOOTM_STATE_OS_GO
+ * then the intent is to boot an OS, so this function will not return
+ * unless the image type is standalone.
+ */
+static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[], int states, bootm_headers_t *images,
+ int boot_progress)
+{
+ boot_os_fn *boot_fn;
+ ulong iflag = 0;
+ int ret = 0;
+
+ images->state |= states;
+
+ /*
+ * Work through the states and see how far we get. We stop on
+ * any error.
+ */
+ if (states & BOOTM_STATE_START)
+ ret = bootm_start(cmdtp, flag, argc, argv);
+
+ if (!ret && (states & BOOTM_STATE_FINDOS))
+ ret = bootm_find_os(cmdtp, flag, argc, argv);
+
+ if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
+ ret = bootm_find_other(cmdtp, flag, argc, argv);
+ argc = 0; /* consume the args */
+ }
+
+ /* Load the OS */
+ if (!ret && (states & BOOTM_STATE_LOADOS)) {
+ ulong load_end;
+
+ ret = bootm_load_os(images->os, &load_end, 0);
+ if (!ret) {
+ lmb_reserve(&images->lmb, images->os.load,
+ (load_end - images->os.load));
+ }
+ }
+
+ /* Relocate the ramdisk */
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+ if (!ret && (states & BOOTM_STATE_RAMDISK)) {
+ ulong rd_len = images->rd_end - images->rd_start;
+
+ ret = boot_ramdisk_high(&images->lmb, images->rd_start,
+ rd_len, &images->initrd_start, &images->initrd_end);
+ if (!ret) {
+ setenv_hex("initrd_start", images->initrd_start);
+ setenv_hex("initrd_end", images->initrd_end);
+ }
+ }
+#endif
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
+ if (!ret && (states & BOOTM_STATE_FDT)) {
+ boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
+ ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
+ &images->ft_len);
+ }
+#endif
+
+ /* From now on, we need the OS boot function */
+ if (ret)
+ return ret;
+ boot_fn = boot_os[images->os.os];
+ if (boot_fn == NULL) {
+ if (iflag)
+ enable_interrupts();
+ printf("ERROR: booting os '%s' (%d) is not supported\n",
+ genimg_get_os_name(images->os.os), images->os.os);
+ bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
+ return 1;
+ }
+
+ /* Call various other states that are not generally used */
+ if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
+ ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
+ if (!ret && (states & BOOTM_STATE_OS_BD_T))
+ ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
+ if (!ret && (states & BOOTM_STATE_OS_PREP))
+ ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
+
+#ifdef CONFIG_TRACE
+ /* Pretend to run the OS, then run a user command */
+ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
+ char *cmd_list = getenv("fakegocmd");
+
+ ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
+ images, boot_fn, &iflag);
+ if (!ret && cmd_list)
+ ret = run_command_list(cmd_list, -1, flag);
+ }
+#endif
+ /* Now run the OS! We hope this doesn't return */
+ if (!ret && (states & BOOTM_STATE_OS_GO))
+ ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
+ images, boot_fn, &iflag);
+
+ /* Deal with any fallout */
+ if (ret < 0) {
+ if (ret == BOOTM_ERR_UNIMPLEMENTED) {
+ if (iflag)
+ enable_interrupts();
+ bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ return 1;
+ } else if (ret == BOOTM_ERR_OVERLAP) {
+ if (images->legacy_hdr_valid) {
+ if (image_get_type(&images->legacy_hdr_os_copy)
+ == IH_TYPE_MULTI)
+ puts("WARNING: legacy format multi component image overwritten\n");
+ } else {
+ puts("ERROR: new format image overwritten - must RESET the board to recover\n");
+ bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
+ ret = BOOTM_ERR_RESET;
+ }
+ }
+ if (ret == BOOTM_ERR_RESET)
+ do_reset(cmdtp, flag, argc, argv);
+ }
+ if (iflag)
+ enable_interrupts();
+ if (ret)
+ puts("subcommand not supported\n");
+
+ return ret;
+}
+
static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
int ret = 0;
long state;
cmd_tbl_t *c;
- boot_os_fn *boot_fn;
- c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
+ c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
+ argc--; argv++;
if (c) {
state = (long)c->cmd;
-
- /* treat start special since it resets the state machine */
- if (state == BOOTM_STATE_START) {
- argc--;
- argv++;
- return bootm_start(cmdtp, flag, argc, argv);
- }
+ if (state == BOOTM_STATE_START)
+ state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
} else {
/* Unrecognized command */
return CMD_RET_USAGE;
}
- if (images.state < BOOTM_STATE_START ||
- images.state >= state) {
+ if (state != BOOTM_STATE_START && images.state >= state) {
printf("Trying to execute a command out of order\n");
return CMD_RET_USAGE;
}
- images.state |= state;
- boot_fn = boot_os[images.os.os];
-
- switch (state) {
- ulong load_end;
- case BOOTM_STATE_START:
- /* should never occur */
- break;
- case BOOTM_STATE_LOADOS:
- ret = bootm_load_os(images.os, &load_end, 0);
- if (ret)
- return ret;
-
- lmb_reserve(&images.lmb, images.os.load,
- (load_end - images.os.load));
- break;
-#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
- case BOOTM_STATE_RAMDISK:
- {
- ulong rd_len = images.rd_end - images.rd_start;
-
- ret = boot_ramdisk_high(&images.lmb, images.rd_start,
- rd_len, &images.initrd_start, &images.initrd_end);
- if (ret)
- return ret;
-
- setenv_hex("initrd_start", images.initrd_start);
- setenv_hex("initrd_end", images.initrd_end);
- }
- break;
-#endif
-#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
- case BOOTM_STATE_FDT:
- {
- boot_fdt_add_mem_rsv_regions(&images.lmb,
- images.ft_addr);
- ret = boot_relocate_fdt(&images.lmb,
- &images.ft_addr, &images.ft_len);
- break;
- }
-#endif
- case BOOTM_STATE_OS_CMDLINE:
- ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images);
- if (ret)
- printf("cmdline subcommand not supported\n");
- break;
- case BOOTM_STATE_OS_BD_T:
- ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images);
- if (ret)
- printf("bdt subcommand not supported\n");
- break;
- case BOOTM_STATE_OS_PREP:
- ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images);
- if (ret)
- printf("prep subcommand not supported\n");
- break;
- case BOOTM_STATE_OS_GO:
- disable_interrupts();
-#ifdef CONFIG_NETCONSOLE
- /*
- * Stop the ethernet stack if NetConsole could have
- * left it up
- */
- eth_halt();
-#endif
- arch_preboot_os();
- boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
- break;
- }
+ ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
return ret;
}
@@ -587,10 +728,6 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- ulong iflag;
- ulong load_end = 0;
- int ret;
- boot_os_fn *boot_fn;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
static int relocated = 0;
@@ -611,11 +748,12 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#endif
/* determine if we have a sub command */
- if (argc > 1) {
+ argc--; argv++;
+ if (argc > 0) {
char *endp;
- simple_strtoul(argv[1], &endp, 16);
- /* endp pointing to NULL means that argv[1] was just a
+ simple_strtoul(argv[0], &endp, 16);
+ /* endp pointing to NULL means that argv[0] was just a
* valid number, pass it along to the normal bootm processing
*
* If endp is ':' or '#' assume a FIT identifier so pass
@@ -627,101 +765,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return do_bootm_subcommand(cmdtp, flag, argc, argv);
}
- if (bootm_start(cmdtp, flag, argc, argv))
- return 1;
-
- /*
- * We have reached the point of no return: we are going to
- * overwrite all exception vector code, so we cannot easily
- * recover from any failures any more...
- */
- iflag = disable_interrupts();
-
-#ifdef CONFIG_NETCONSOLE
- /* Stop the ethernet stack if NetConsole could have left it up */
- eth_halt();
-#endif
-
-#if defined(CONFIG_CMD_USB)
- /*
- * turn off USB to prevent the host controller from writing to the
- * SDRAM while Linux is booting. This could happen (at least for OHCI
- * controller), because the HCCA (Host Controller Communication Area)
- * lies within the SDRAM and the host controller writes continously to
- * this area (as busmaster!). The HccaFrameNumber is for example
- * updated every 1 ms within the HCCA structure in SDRAM! For more
- * details see the OpenHCI specification.
- */
- usb_stop();
-#endif
-
- ret = bootm_load_os(images.os, &load_end, 1);
-
- if (ret < 0) {
- if (ret == BOOTM_ERR_RESET)
- do_reset(cmdtp, flag, argc, argv);
- if (ret == BOOTM_ERR_OVERLAP) {
- if (images.legacy_hdr_valid) {
- image_header_t *hdr;
- hdr = &images.legacy_hdr_os_copy;
- if (image_get_type(hdr) == IH_TYPE_MULTI)
- puts("WARNING: legacy format multi "
- "component image "
- "overwritten\n");
- } else {
- puts("ERROR: new format image overwritten - "
- "must RESET the board to recover\n");
- bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
- do_reset(cmdtp, flag, argc, argv);
- }
- }
- if (ret == BOOTM_ERR_UNIMPLEMENTED) {
- if (iflag)
- enable_interrupts();
- bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
- return 1;
- }
- }
-
- lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
-
- if (images.os.type == IH_TYPE_STANDALONE) {
- if (iflag)
- enable_interrupts();
- /* This may return when 'autostart' is 'no' */
- bootm_start_standalone(iflag, argc, argv);
- return 0;
- }
-
- bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS);
-
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
- if (images.os.os == IH_OS_LINUX)
- fixup_silent_linux();
-#endif
-
- boot_fn = boot_os[images.os.os];
-
- if (boot_fn == NULL) {
- if (iflag)
- enable_interrupts();
- printf("ERROR: booting os '%s' (%d) is not supported\n",
- genimg_get_os_name(images.os.os), images.os.os);
- bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
- return 1;
- }
-
- arch_preboot_os();
-
- boot_fn(0, argc, argv, &images);
-
- bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
-#ifdef DEBUG
- puts("\n## Control returned to monitor - resetting...\n");
-#endif
- do_reset(cmdtp, flag, argc, argv);
-
- return 1;
+ return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
+ BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
+ BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP |
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1);
}
int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
@@ -816,22 +863,22 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
#endif
/* find out kernel image address */
- if (argc < 2) {
+ if (argc < 1) {
img_addr = load_addr;
debug("* kernel: default image load address = 0x%08lx\n",
load_addr);
#if defined(CONFIG_FIT)
- } else if (fit_parse_conf(argv[1], load_addr, &img_addr,
+ } else if (fit_parse_conf(argv[0], load_addr, &img_addr,
&fit_uname_config)) {
debug("* kernel: config '%s' from image at 0x%08lx\n",
fit_uname_config, img_addr);
- } else if (fit_parse_subimage(argv[1], load_addr, &img_addr,
+ } else if (fit_parse_subimage(argv[0], load_addr, &img_addr,
&fit_uname_kernel)) {
debug("* kernel: subimage '%s' from image at 0x%08lx\n",
fit_uname_kernel, img_addr);
#endif
} else {
- img_addr = simple_strtoul(argv[1], NULL, 16);
+ img_addr = simple_strtoul(argv[0], NULL, 16);
debug("* kernel: cmdline image address = 0x%08lx\n", img_addr);
}
@@ -1346,6 +1393,19 @@ static void fixup_silent_linux(void)
}
#endif /* CONFIG_SILENT_CONSOLE */
+#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
+static void copy_args(char *dest, int argc, char * const argv[], char delim)
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (i > 0)
+ *dest++ = delim;
+ strcpy(dest, argv[i]);
+ dest += strlen(argv[i]);
+ }
+}
+#endif
/*******************************************************************/
/* OS booting routines */
@@ -1401,20 +1461,14 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[],
consdev = "scc3";
#endif
- if (argc > 2) {
+ if (argc > 0) {
ulong len;
int i;
- for (i = 2, len = 0; i < argc; i += 1)
+ for (i = 0, len = 0; i < argc; i += 1)
len += strlen(argv[i]) + 1;
cmdline = malloc(len);
-
- for (i = 2, len = 0; i < argc; i += 1) {
- if (i > 2)
- cmdline[len++] = ' ';
- strcpy(&cmdline[len], argv[i]);
- len += strlen(argv[i]);
- }
+ copy_args(cmdline, argc, argv, ' ');
} else if ((cmdline = getenv("bootargs")) == NULL) {
cmdline = "";
}
@@ -1533,6 +1587,7 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
void (*entry_point)(void);
+ char *s;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
@@ -1544,6 +1599,20 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],
}
#endif
+ /* See README.plan9 */
+ s = getenv("confaddr");
+ if (s != NULL) {
+ char *confaddr = (char *)simple_strtoul(s, NULL, 16);
+
+ if (argc > 0) {
+ copy_args(confaddr, argc, argv, '\n');
+ } else {
+ s = getenv("bootargs");
+ if (s != NULL)
+ strcpy(confaddr, s);
+ }
+ }
+
entry_point = (void (*)(void))images->ep;
printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
@@ -1663,9 +1732,8 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
int ret;
void *zi_start, *zi_end;
- memset(images, 0, sizeof(bootm_headers_t));
-
- boot_start_lmb(images);
+ ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
+ images, 1);
/* Setup Linux kernel zImage entry point */
if (argc < 2) {
@@ -1684,73 +1752,25 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);
- /* Find ramdisk */
- ret = boot_get_ramdisk(argc, argv, images, IH_INITRD_ARCH,
- &images->rd_start, &images->rd_end);
- if (ret) {
- puts("Ramdisk image is corrupt or invalid\n");
- return 1;
- }
+ ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER,
+ images, 1);
-#if defined(CONFIG_OF_LIBFDT)
- /* find flattened device tree */
- ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images,
- &images->ft_addr, &images->ft_len);
- if (ret) {
- puts("Could not find a valid device tree\n");
- return 1;
- }
-
- set_working_fdt_addr(images->ft_addr);
-#endif
-
- return 0;
+ return ret;
}
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
bootm_headers_t images;
+ int ret;
if (bootz_start(cmdtp, flag, argc, argv, &images))
return 1;
- /*
- * We have reached the point of no return: we are going to
- * overwrite all exception vector code, so we cannot easily
- * recover from any failures any more...
- */
- disable_interrupts();
+ ret = do_bootm_states(cmdtp, flag, argc, argv,
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO,
+ &images, 1);
-#ifdef CONFIG_NETCONSOLE
- /* Stop the ethernet stack if NetConsole could have left it up */
- eth_halt();
-#endif
-
-#if defined(CONFIG_CMD_USB)
- /*
- * turn off USB to prevent the host controller from writing to the
- * SDRAM while Linux is booting. This could happen (at least for OHCI
- * controller), because the HCCA (Host Controller Communication Area)
- * lies within the SDRAM and the host controller writes continously to
- * this area (as busmaster!). The HccaFrameNumber is for example
- * updated every 1 ms within the HCCA structure in SDRAM! For more
- * details see the OpenHCI specification.
- */
- usb_stop();
-#endif
-
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
- fixup_silent_linux();
-#endif
- arch_preboot_os();
-
- do_bootm_linux(0, argc, argv, &images);
-#ifdef DEBUG
- puts("\n## Control returned to monitor - resetting...\n");
-#endif
- do_reset(cmdtp, flag, argc, argv);
-
- return 1;
+ return ret;
}
#ifdef CONFIG_SYS_LONGHELP
diff --git a/common/cmd_ide.c b/common/cmd_ide.c
index 78b4aa7..59e95df 100644
--- a/common/cmd_ide.c
+++ b/common/cmd_ide.c
@@ -830,7 +830,7 @@ static void ide_ident(block_dev_desc_t *dev_desc)
/* ------------------------------------------------------------------------- */
-ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
+ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer)
{
ulong n = 0;
unsigned char c;
@@ -844,7 +844,7 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
lba48 = 1;
}
#endif
- debug("ide_read dev %d start %lX, blocks " LBAF " buffer at %lX\n",
+ debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",
device, blknr, blkcnt, (ulong) buffer);
ide_led(DEVICE_LED(device), 1); /* LED on */
@@ -934,8 +934,8 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
ATA_STAT_DRQ) {
- printf("Error (no IRQ) dev %d blk %ld: status %#02x\n",
- device, blknr, c);
+ printf("Error (no IRQ) dev %d blk " LBAF ": status "
+ "%#02x\n", device, blknr, c);
break;
}
@@ -954,7 +954,7 @@ IDE_READ_E:
/* ------------------------------------------------------------------------- */
-ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer)
+ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer)
{
ulong n = 0;
unsigned char c;
@@ -1022,8 +1022,8 @@ ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer)
if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
ATA_STAT_DRQ) {
- printf("Error (no IRQ) dev %d blk %ld: status %#02x\n",
- device, blknr, c);
+ printf("Error (no IRQ) dev %d blk " LBAF ": status "
+ "%#02x\n", device, blknr, c);
goto WR_OUT;
}
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index 6df00b1..77eafa0 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -551,6 +551,8 @@ static int do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc,
*cp++;
}
unmap_sysmem(buf);
+
+ return 0;
}
#ifdef CONFIG_LOOPW
diff --git a/common/cmd_trace.c b/common/cmd_trace.c
new file mode 100644
index 0000000..ec3137a
--- /dev/null
+++ b/common/cmd_trace.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <trace.h>
+#include <asm/io.h>
+
+static int get_args(int argc, char * const argv[], char **buff,
+ size_t *buff_ptr, size_t *buff_size)
+{
+ if (argc < 2)
+ return -1;
+ if (argc < 4) {
+ *buff_size = getenv_ulong("profsize", 16, 0);
+ *buff = map_sysmem(getenv_ulong("profbase", 16, 0),
+ *buff_size);
+ *buff_ptr = getenv_ulong("profoffset", 16, 0);
+ } else {
+ *buff_size = simple_strtoul(argv[3], NULL, 16);
+ *buff = map_sysmem(simple_strtoul(argv[2], NULL, 16),
+ *buff_size);
+ *buff_ptr = 0;
+ };
+ return 0;
+}
+
+static int create_func_list(int argc, char * const argv[])
+{
+ size_t buff_size, avail, buff_ptr, used;
+ unsigned int needed;
+ char *buff;
+ int err;
+
+ if (get_args(argc, argv, &buff, &buff_ptr, &buff_size))
+ return -1;
+
+ avail = buff_size - buff_ptr;
+ err = trace_list_functions(buff + buff_ptr, avail, &needed);
+ if (err)
+ printf("Error: truncated (%#x bytes needed)\n", needed);
+ used = min(avail, needed);
+ printf("Function trace dumped to %08lx, size %#zx\n",
+ (ulong)map_to_sysmem(buff + buff_ptr), used);
+ setenv_hex("profbase", map_to_sysmem(buff));
+ setenv_hex("profsize", buff_size);
+ setenv_hex("profoffset", buff_ptr + used);
+
+ return 0;
+}
+
+static int create_call_list(int argc, char * const argv[])
+{
+ size_t buff_size, avail, buff_ptr, used;
+ unsigned int needed;
+ char *buff;
+ int err;
+
+ if (get_args(argc, argv, &buff, &buff_ptr, &buff_size))
+ return -1;
+
+ avail = buff_size - buff_ptr;
+ err = trace_list_calls(buff + buff_ptr, avail, &needed);
+ if (err)
+ printf("Error: truncated (%#x bytes needed)\n", needed);
+ used = min(avail, needed);
+ printf("Call list dumped to %08lx, size %#zx\n",
+ (ulong)map_to_sysmem(buff + buff_ptr), used);
+
+ setenv_hex("profbase", map_to_sysmem(buff));
+ setenv_hex("profsize", buff_size);
+ setenv_hex("profoffset", buff_ptr + used);
+
+ return 0;
+}
+
+int do_trace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const char *cmd = argc < 2 ? NULL : argv[1];
+
+ if (!cmd)
+ return cmd_usage(cmdtp);
+ switch (*cmd) {
+ case 'p':
+ trace_set_enabled(0);
+ break;
+ case 'c':
+ if (create_call_list(argc, argv))
+ return cmd_usage(cmdtp);
+ break;
+ case 'r':
+ trace_set_enabled(1);
+ break;
+ case 'f':
+ if (create_func_list(argc, argv))
+ return cmd_usage(cmdtp);
+ break;
+ case 's':
+ trace_print_stats();
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ trace, 4, 1, do_trace,
+ "trace utility commands",
+ "stats - display tracing statistics\n"
+ "trace pause - pause tracing\n"
+ "trace resume - resume tracing\n"
+ "trace funclist [<addr> <size>] - dump function list into buffer\n"
+ "trace calls [<addr> <size>] "
+ "- dump function call trace into buffer"
+);
diff --git a/common/image-fdt.c b/common/image-fdt.c
index 0d421d9..d99f444 100644
--- a/common/image-fdt.c
+++ b/common/image-fdt.c
@@ -248,13 +248,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
ulong default_addr;
int fdt_noffset;
#endif
+ const char *select = NULL;
*of_flat_tree = NULL;
*of_size = 0;
- if (argc > 3 || genimg_has_config(images)) {
+ if (argc > 2)
+ select = argv[2];
+ if (select || genimg_has_config(images)) {
#if defined(CONFIG_FIT)
- if (argc > 3) {
+ if (select) {
/*
* If the FDT blob comes from the FIT image and the
* FIT image address is omitted in the command line
@@ -268,18 +271,18 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
else
default_addr = load_addr;
- if (fit_parse_conf(argv[3], default_addr,
+ if (fit_parse_conf(select, default_addr,
&fdt_addr, &fit_uname_config)) {
debug("* fdt: config '%s' from image at 0x%08lx\n",
fit_uname_config, fdt_addr);
- } else if (fit_parse_subimage(argv[3], default_addr,
+ } else if (fit_parse_subimage(select, default_addr,
&fdt_addr, &fit_uname_fdt)) {
debug("* fdt: subimage '%s' from image at 0x%08lx\n",
fit_uname_fdt, fdt_addr);
} else
#endif
{
- fdt_addr = simple_strtoul(argv[3], NULL, 16);
+ fdt_addr = simple_strtoul(select, NULL, 16);
debug("* fdt: cmdline image address = 0x%08lx\n",
fdt_addr);
}
diff --git a/common/image-fit.c b/common/image-fit.c
index f40f160..b75e119 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -234,42 +234,45 @@ void fit_print_contents(const void *fit)
* @fit: pointer to the FIT format image header
* @noffset: offset of the hash node
* @p: pointer to prefix string
+ * @type: Type of information to print ("hash" or "sign")
*
* fit_image_print_data() lists properies for the processed hash node
*
+ * This function avoid using puts() since it prints a newline on the host
+ * but does not in U-Boot.
+ *
* returns:
* no returned results
*/
-static void fit_image_print_data(const void *fit, int noffset, const char *p)
+static void fit_image_print_data(const void *fit, int noffset, const char *p,
+ const char *type)
{
- char *algo;
+ const char *keyname;
uint8_t *value;
int value_len;
- int i, ret;
-
- /*
- * Check subnode name, must be equal to "hash".
- * Multiple hash nodes require unique unit node
- * names, e.g. hash@1, hash@2, etc.
- */
- if (strncmp(fit_get_name(fit, noffset, NULL),
- FIT_HASH_NODENAME,
- strlen(FIT_HASH_NODENAME)) != 0)
- return;
+ char *algo;
+ int required;
+ int ret, i;
- debug("%s Hash node: '%s'\n", p,
+ debug("%s %s node: '%s'\n", p, type,
fit_get_name(fit, noffset, NULL));
-
- printf("%s Hash algo: ", p);
+ printf("%s %s algo: ", p, type);
if (fit_image_hash_get_algo(fit, noffset, &algo)) {
printf("invalid/unsupported\n");
return;
}
- printf("%s\n", algo);
+ printf("%s", algo);
+ keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+ required = fdt_getprop(fit, noffset, "required", NULL) != NULL;
+ if (keyname)
+ printf(":%s", keyname);
+ if (required)
+ printf(" (required)");
+ printf("\n");
ret = fit_image_hash_get_value(fit, noffset, &value,
&value_len);
- printf("%s Hash value: ", p);
+ printf("%s %s value: ", p, type);
if (ret) {
printf("unavailable\n");
} else {
@@ -278,7 +281,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p)
printf("\n");
}
- debug("%s Hash len: %d\n", p, value_len);
+ debug("%s %s len: %d\n", p, type, value_len);
+
+ /* Signatures have a time stamp */
+ if (IMAGE_ENABLE_TIMESTAMP && keyname) {
+ time_t timestamp;
+
+ printf("%s Timestamp: ", p);
+ if (fit_get_timestamp(fit, noffset, &timestamp))
+ printf("unavailable\n");
+ else
+ genimg_print_time(timestamp);
+ }
}
/**
@@ -303,8 +317,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset,
* names, e.g. hash@1, hash@2, signature@1, signature@2, etc.
*/
name = fit_get_name(fit, noffset, NULL);
- if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME)))
- fit_image_print_data(fit, noffset, p);
+ if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) {
+ fit_image_print_data(fit, noffset, p, "Hash");
+ } else if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ fit_image_print_data(fit, noffset, p, "Sign");
+ }
}
/**
@@ -944,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset)
{
const void *data;
size_t size;
- int noffset;
+ int noffset = 0;
char *err_msg = "";
+ int verify_all = 1;
+ int ret;
/* Get image data and data length */
if (fit_image_get_data(fit, image_noffset, &data, &size)) {
err_msg = "Can't get image data/size";
- return 0;
+ goto error;
+ }
+
+ /* Verify all required signatures */
+ if (IMAGE_ENABLE_VERIFY &&
+ fit_image_verify_required_sigs(fit, image_noffset, data, size,
+ gd_fdt_blob(), &verify_all)) {
+ err_msg = "Unable to verify required signature";
+ goto error;
}
/* Process all hash subnodes of the component image node */
@@ -970,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset)
&err_msg))
goto error;
puts("+ ");
+ } else if (IMAGE_ENABLE_VERIFY && verify_all &&
+ !strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_check_sig(fit, noffset, data,
+ size, -1, &err_msg);
+ if (ret)
+ puts("- ");
+ else
+ puts("+ ");
}
}
diff --git a/common/image-sig.c b/common/image-sig.c
new file mode 100644
index 0000000..5d907cf
--- /dev/null
+++ b/common/image-sig.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <time.h>
+#else
+#include <common.h>
+#include <malloc.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* !USE_HOSTCC*/
+#include <image.h>
+#include <rsa.h>
+
+#define IMAGE_MAX_HASHED_NODES 100
+
+struct image_sig_algo image_sig_algos[] = {
+ {
+ "sha1,rsa2048",
+ rsa_sign,
+ rsa_add_verify_data,
+ rsa_verify,
+ }
+};
+
+struct image_sig_algo *image_get_sig_algo(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) {
+ if (!strcmp(image_sig_algos[i].name, name))
+ return &image_sig_algos[i];
+ }
+
+ return NULL;
+}
+
+/**
+ * fit_region_make_list() - Make a list of image regions
+ *
+ * Given a list of fdt_regions, create a list of image_regions. This is a
+ * simple conversion routine since the FDT and image code use different
+ * structures.
+ *
+ * @fit: FIT image
+ * @fdt_regions: Pointer to FDT regions
+ * @count: Number of FDT regions
+ * @region: Pointer to image regions, which must hold @count records. If
+ * region is NULL, then (except for an SPL build) the array will be
+ * allocated.
+ * @return: Pointer to image regions
+ */
+struct image_region *fit_region_make_list(const void *fit,
+ struct fdt_region *fdt_regions, int count,
+ struct image_region *region)
+{
+ int i;
+
+ debug("Hash regions:\n");
+ debug("%10s %10s\n", "Offset", "Size");
+
+ /*
+ * Use malloc() except in SPL (to save code size). In SPL the caller
+ * must allocate the array.
+ */
+#ifndef CONFIG_SPL_BUILD
+ if (!region)
+ region = calloc(sizeof(*region), count);
+#endif
+ if (!region)
+ return NULL;
+ for (i = 0; i < count; i++) {
+ debug("%10x %10x\n", fdt_regions[i].offset,
+ fdt_regions[i].size);
+ region[i].data = fit + fdt_regions[i].offset;
+ region[i].size = fdt_regions[i].size;
+ }
+
+ return region;
+}
+
+static int fit_image_setup_verify(struct image_sign_info *info,
+ const void *fit, int noffset, int required_keynode,
+ char **err_msgp)
+{
+ char *algo_name;
+
+ if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+ *err_msgp = "Can't get hash algo property";
+ return -1;
+ }
+ memset(info, '\0', sizeof(*info));
+ info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+ info->fit = (void *)fit;
+ info->node_offset = noffset;
+ info->algo = image_get_sig_algo(algo_name);
+ info->fdt_blob = gd_fdt_blob();
+ info->required_keynode = required_keynode;
+ printf("%s:%s", algo_name, info->keyname);
+
+ if (!info->algo) {
+ *err_msgp = "Unknown signature algorithm";
+ return -1;
+ }
+
+ return 0;
+}
+
+int fit_image_check_sig(const void *fit, int noffset, const void *data,
+ size_t size, int required_keynode, char **err_msgp)
+{
+ struct image_sign_info info;
+ struct image_region region;
+ uint8_t *fit_value;
+ int fit_value_len;
+
+ *err_msgp = NULL;
+ if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+ err_msgp))
+ return -1;
+
+ if (fit_image_hash_get_value(fit, noffset, &fit_value,
+ &fit_value_len)) {
+ *err_msgp = "Can't get hash value property";
+ return -1;
+ }
+
+ region.data = data;
+ region.size = size;
+
+ if (info.algo->verify(&info, &region, 1, fit_value, fit_value_len)) {
+ *err_msgp = "Verification failed";
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_image_verify_sig(const void *fit, int image_noffset,
+ const char *data, size_t size, const void *sig_blob,
+ int sig_offset)
+{
+ int noffset;
+ char *err_msg = "";
+ int verified = 0;
+ int ret;
+
+ /* Process all hash subnodes of the component image node */
+ for (noffset = fdt_first_subnode(fit, image_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_check_sig(fit, noffset, data,
+ size, -1, &err_msg);
+ if (ret) {
+ puts("- ");
+ } else {
+ puts("+ ");
+ verified = 1;
+ break;
+ }
+ }
+ }
+
+ if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+ err_msg = "Corrupted or truncated tree";
+ goto error;
+ }
+
+ return verified ? 0 : -EPERM;
+
+error:
+ printf(" error!\n%s for '%s' hash node in '%s' image node\n",
+ err_msg, fit_get_name(fit, noffset, NULL),
+ fit_get_name(fit, image_noffset, NULL));
+ return -1;
+}
+
+int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+ const char *data, size_t size, const void *sig_blob,
+ int *no_sigsp)
+{
+ int verify_count = 0;
+ int noffset;
+ int sig_node;
+
+ /* Work out what we need to verify */
+ *no_sigsp = 1;
+ sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+ if (sig_node < 0) {
+ debug("%s: No signature node found: %s\n", __func__,
+ fdt_strerror(sig_node));
+ return 0;
+ }
+
+ for (noffset = fdt_first_subnode(sig_blob, sig_node);
+ noffset >= 0;
+ noffset = fdt_next_subnode(sig_blob, noffset)) {
+ const char *required;
+ int ret;
+
+ required = fdt_getprop(sig_blob, noffset, "required", NULL);
+ if (!required || strcmp(required, "image"))
+ continue;
+ ret = fit_image_verify_sig(fit, image_noffset, data, size,
+ sig_blob, noffset);
+ if (ret) {
+ printf("Failed to verify required signature '%s'\n",
+ fit_get_name(sig_blob, noffset, NULL));
+ return ret;
+ }
+ verify_count++;
+ }
+
+ if (verify_count)
+ *no_sigsp = 0;
+
+ return 0;
+}
+
+int fit_config_check_sig(const void *fit, int noffset, int required_keynode,
+ char **err_msgp)
+{
+ char * const exc_prop[] = {"data"};
+ const char *prop, *end, *name;
+ struct image_sign_info info;
+ const uint32_t *strings;
+ uint8_t *fit_value;
+ int fit_value_len;
+ int max_regions;
+ int i, prop_len;
+ char path[200];
+ int count;
+
+ debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
+ fit_get_name(fit, noffset, NULL),
+ fit_get_name(gd_fdt_blob(), required_keynode, NULL));
+ *err_msgp = NULL;
+ if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+ err_msgp))
+ return -1;
+
+ if (fit_image_hash_get_value(fit, noffset, &fit_value,
+ &fit_value_len)) {
+ *err_msgp = "Can't get hash value property";
+ return -1;
+ }
+
+ /* Count the number of strings in the property */
+ prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
+ end = prop ? prop + prop_len : prop;
+ for (name = prop, count = 0; name < end; name++)
+ if (!*name)
+ count++;
+ if (!count) {
+ *err_msgp = "Can't get hashed-nodes property";
+ return -1;
+ }
+
+ /* Add a sanity check here since we are using the stack */
+ if (count > IMAGE_MAX_HASHED_NODES) {
+ *err_msgp = "Number of hashed nodes exceeds maximum";
+ return -1;
+ }
+
+ /* Create a list of node names from those strings */
+ char *node_inc[count];
+
+ debug("Hash nodes (%d):\n", count);
+ for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
+ debug(" '%s'\n", name);
+ node_inc[i] = (char *)name;
+ }
+
+ /*
+ * Each node can generate one region for each sub-node. Allow for
+ * 7 sub-nodes (hash@1, signature@1, etc.) and some extra.
+ */
+ max_regions = 20 + count * 7;
+ struct fdt_region fdt_regions[max_regions];
+
+ /* Get a list of regions to hash */
+ count = fdt_find_regions(fit, node_inc, count,
+ exc_prop, ARRAY_SIZE(exc_prop),
+ fdt_regions, max_regions - 1,
+ path, sizeof(path), 0);
+ if (count < 0) {
+ *err_msgp = "Failed to hash configuration";
+ return -1;
+ }
+ if (count == 0) {
+ *err_msgp = "No data to hash";
+ return -1;
+ }
+ if (count >= max_regions - 1) {
+ *err_msgp = "Too many hash regions";
+ return -1;
+ }
+
+ /* Add the strings */
+ strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
+ if (strings) {
+ fdt_regions[count].offset = fdt_off_dt_strings(fit) +
+ fdt32_to_cpu(strings[0]);
+ fdt_regions[count].size = fdt32_to_cpu(strings[1]);
+ count++;
+ }
+
+ /* Allocate the region list on the stack */
+ struct image_region region[count];
+
+ fit_region_make_list(fit, fdt_regions, count, region);
+ if (info.algo->verify(&info, region, count, fit_value,
+ fit_value_len)) {
+ *err_msgp = "Verification failed";
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_config_verify_sig(const void *fit, int conf_noffset,
+ const void *sig_blob, int sig_offset)
+{
+ int noffset;
+ char *err_msg = "";
+ int verified = 0;
+ int ret;
+
+ /* Process all hash subnodes of the component conf node */
+ for (noffset = fdt_first_subnode(fit, conf_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ if (!strncmp(name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_config_check_sig(fit, noffset, sig_offset,
+ &err_msg);
+ if (ret) {
+ puts("- ");
+ } else {
+ puts("+ ");
+ verified = 1;
+ break;
+ }
+ }
+ }
+
+ if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+ err_msg = "Corrupted or truncated tree";
+ goto error;
+ }
+
+ return verified ? 0 : -EPERM;
+
+error:
+ printf(" error!\n%s for '%s' hash node in '%s' config node\n",
+ err_msg, fit_get_name(fit, noffset, NULL),
+ fit_get_name(fit, conf_noffset, NULL));
+ return -1;
+}
+
+int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
+ const void *sig_blob)
+{
+ int noffset;
+ int sig_node;
+
+ /* Work out what we need to verify */
+ sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+ if (sig_node < 0) {
+ debug("%s: No signature node found: %s\n", __func__,
+ fdt_strerror(sig_node));
+ return 0;
+ }
+
+ for (noffset = fdt_first_subnode(sig_blob, sig_node);
+ noffset >= 0;
+ noffset = fdt_next_subnode(sig_blob, noffset)) {
+ const char *required;
+ int ret;
+
+ required = fdt_getprop(sig_blob, noffset, "required", NULL);
+ if (!required || strcmp(required, "conf"))
+ continue;
+ ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
+ noffset);
+ if (ret) {
+ printf("Failed to verify required signature '%s'\n",
+ fit_get_name(sig_blob, noffset, NULL));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int fit_config_verify(const void *fit, int conf_noffset)
+{
+ return !fit_config_verify_required_sigs(fit, conf_noffset,
+ gd_fdt_blob());
+}
diff --git a/common/image.c b/common/image.c
index f863502..1be384f 100644
--- a/common/image.c
+++ b/common/image.c
@@ -816,20 +816,23 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
ulong default_addr;
int rd_noffset;
#endif
+ const char *select = NULL;
*rd_start = 0;
*rd_end = 0;
+ if (argc >= 2)
+ select = argv[1];
/*
* Look for a '-' which indicates to ignore the
* ramdisk argument
*/
- if ((argc >= 3) && (strcmp(argv[2], "-") == 0)) {
+ if (select && strcmp(select, "-") == 0) {
debug("## Skipping init Ramdisk\n");
rd_len = rd_data = 0;
- } else if (argc >= 3 || genimg_has_config(images)) {
+ } else if (select || genimg_has_config(images)) {
#if defined(CONFIG_FIT)
- if (argc >= 3) {
+ if (select) {
/*
* If the init ramdisk comes from the FIT image and
* the FIT image address is omitted in the command
@@ -841,12 +844,12 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
else
default_addr = load_addr;
- if (fit_parse_conf(argv[2], default_addr,
- &rd_addr, &fit_uname_config)) {
+ if (fit_parse_conf(select, default_addr,
+ &rd_addr, &fit_uname_config)) {
debug("* ramdisk: config '%s' from image at "
"0x%08lx\n",
fit_uname_config, rd_addr);
- } else if (fit_parse_subimage(argv[2], default_addr,
+ } else if (fit_parse_subimage(select, default_addr,
&rd_addr, &fit_uname_ramdisk)) {
debug("* ramdisk: subimage '%s' from image at "
"0x%08lx\n",
@@ -854,7 +857,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
} else
#endif
{
- rd_addr = simple_strtoul(argv[2], NULL, 16);
+ rd_addr = simple_strtoul(select, NULL, 16);
debug("* ramdisk: cmdline image address = "
"0x%08lx\n",
rd_addr);
@@ -918,7 +921,10 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
#endif
default:
#ifdef CONFIG_SUPPORT_RAW_INITRD
- if (argc >= 3 && (end = strchr(argv[2], ':'))) {
+ end = NULL;
+ if (select)
+ end = strchr(select, ':');
+ if (end) {
rd_len = simple_strtoul(++end, NULL, 16);
rd_data = rd_addr;
} else
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 457970f..4599d03 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -170,9 +170,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
block_dev_desc_t *dev_desc);
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
struct us_data *ss);
-unsigned long usb_stor_read(int device, unsigned long blknr,
+unsigned long usb_stor_read(int device, lbaint_t blknr,
lbaint_t blkcnt, void *buffer);
-unsigned long usb_stor_write(int device, unsigned long blknr,
+unsigned long usb_stor_write(int device, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer);
struct usb_device * usb_get_dev_index(int index);
void uhci_show_temp_int_td(void);
@@ -1054,7 +1054,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,
}
#endif /* CONFIG_USB_BIN_FIXUP */
-unsigned long usb_stor_read(int device, unsigned long blknr,
+unsigned long usb_stor_read(int device, lbaint_t blknr,
lbaint_t blkcnt, void *buffer)
{
lbaint_t start, blks;
@@ -1127,7 +1127,7 @@ retry_it:
return blkcnt;
}
-unsigned long usb_stor_write(int device, unsigned long blknr,
+unsigned long usb_stor_write(int device, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer)
{
lbaint_t start, blks;
diff --git a/config.mk b/config.mk
index ddf350e..5a91203 100644
--- a/config.mk
+++ b/config.mk
@@ -96,6 +96,7 @@ HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp")
HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")
else
HOSTCC = gcc
+HOSTLIBS += -lssl -lcrypto
endif
ifeq ($(HOSTOS),cygwin)
@@ -268,6 +269,16 @@ CFLAGS += $(CFLAGS_WARN)
CFLAGS_STACK := $(call cc-option,-fstack-usage)
CFLAGS += $(CFLAGS_STACK)
+BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%))
+
+ifeq ($(findstring examples/,$(BCURDIR)),)
+ifeq ($(CONFIG_SPL_BUILD),)
+ifdef FTRACE
+CFLAGS += -finstrument-functions -DFTRACE
+endif
+endif
+endif
+
# $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g<format>
# option to the assembler.
AFLAGS_DEBUG :=
@@ -330,7 +341,6 @@ export CONFIG_SYS_TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS
#########################################################################
# Allow boards to use custom optimize flags on a per dir/file basis
-BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%))
ALL_AFLAGS = $(AFLAGS) $(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR))
ALL_CFLAGS = $(CFLAGS) $(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR))
EXTRA_CPPFLAGS = $(CPPFLAGS_$(BCURDIR)/$(@F)) $(CPPFLAGS_$(BCURDIR))
diff --git a/doc/README.plan9 b/doc/README.plan9
new file mode 100644
index 0000000..2d3d0e0
--- /dev/null
+++ b/doc/README.plan9
@@ -0,0 +1,18 @@
+Plan 9 from Bell Labs kernel images require additional setup to pass
+configuration information to the kernel. An environment variable named
+confaddr must be defined with the same value as CONFADDR (see mem.h).
+Use of this facility is optional, but should be preferable to manual
+configuration.
+
+When booting an image, arguments supplied to the bootm command will be
+copied to CONFADDR. If no arguments are specified, the contents of the
+bootargs environment variable will be copied.
+
+If no command line arguments or bootargs are defined, CONFADDR is left
+uninitialized to permit manual configuration. For example, PC-style
+configuration could be simulated by issuing a fatload in bootcmd:
+
+ # setenv bootcmd fatload mmc 0 $confaddr plan9.ini; ...; bootm
+
+Steven Stallion
+June 2013
diff --git a/doc/README.trace b/doc/README.trace
new file mode 100644
index 0000000..b535c06
--- /dev/null
+++ b/doc/README.trace
@@ -0,0 +1,361 @@
+#
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundatio; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+Tracing in U-Boot
+=================
+
+U-Boot supports a simple tracing feature which allows a record of excecution
+to be collected and sent to a host machine for analysis. At present the
+main use for this is to profile boot time.
+
+
+Overview
+--------
+
+The trace feature uses GCC's instrument-functions feature to trace all
+function entry/exit points. These are then recorded in a memory buffer.
+The memory buffer can be saved to the host over a network link using
+tftpput or by writing to an attached memory device such as MMC.
+
+On the host, the file is first converted with a tool called 'proftool',
+which extracts useful information from it. The resulting trace output
+resembles that emitted by Linux's ftrace feature, so can be visually
+displayed by pytimechart.
+
+
+Quick-start using Sandbox
+-------------------------
+
+Sandbox is a build of U-Boot that can run under Linux so it is a convenient
+way of trying out tracing before you use it on your actual board. To do
+this, follow these steps:
+
+Add the following to include/configs/sandbox.h (if not already there)
+
+#define CONFIG_TRACE
+#define CONFIG_CMD_TRACE
+#define CONFIG_TRACE_BUFFER_SIZE (16 << 20)
+#define CONFIG_TRACE_EARLY_SIZE (8 << 20)
+#define CONFIG_TRACE_EARLY
+#define CONFIG_TRACE_EARLY_ADDR 0x00100000
+
+Build sandbox U-Boot with tracing enabled:
+
+$ make FTRACE=1 O=sandbox sandbox_config
+$ make FTRACE=1 O=sandbox
+
+Run sandbox, wait for a bit of trace information to appear, and then capture
+a trace:
+
+$ ./sandbox/u-boot
+
+
+U-Boot 2013.04-rc2-00100-ga72fcef (Apr 17 2013 - 19:25:24)
+
+DRAM: 128 MiB
+trace: enabled
+Using default environment
+
+In: serial
+Out: serial
+Err: serial
+=>trace stats
+ 671,406 function sites
+ 69,712 function calls
+ 0 untracked function calls
+ 73,373 traced function calls
+ 16 maximum observed call depth
+ 15 call depth limit
+ 66,491 calls not traced due to depth
+=>trace stats
+ 671,406 function sites
+ 1,279,450 function calls
+ 0 untracked function calls
+ 950,490 traced function calls (333217 dropped due to overflow)
+ 16 maximum observed call depth
+ 15 call depth limit
+ 1,275,767 calls not traced due to depth
+=>trace calls 0 e00000
+Call list dumped to 00000000, size 0xae0a40
+=>print
+baudrate=115200
+profbase=0
+profoffset=ae0a40
+profsize=e00000
+stderr=serial
+stdin=serial
+stdout=serial
+
+Environment size: 117/8188 bytes
+=>sb save host 0 trace 0 ${profoffset}
+11405888 bytes written in 10 ms (1.1 GiB/s)
+=>reset
+
+
+Then run proftool to convert the trace information to ftrace format.
+
+$ ./sandbox/tools/proftool -m sandbox/System.map -p trace dump-ftrace >trace.txt
+
+Finally run pytimechart to display it:
+
+$ pytimechart trace.txt
+
+Using this tool you can zoom and pan across the trace, with the function
+calls on the left and little marks representing the start and end of each
+function.
+
+
+CONFIG Options
+--------------
+
+- CONFIG_TRACE
+ Enables the trace feature in U-Boot.
+
+- CONFIG_CMD_TRACE
+ Enables the trace command.
+
+- CONFIG_TRACE_BUFFER_SIZE
+ Size of trace buffer to allocate for U-Boot. This buffer is
+ used after relocation, as a place to put function tracing
+ information. The address of the buffer is determined by
+ the relocation code.
+
+- CONFIG_TRACE_EARLY
+ Define this to start tracing early, before relocation.
+
+- CONFIG_TRACE_EARLY_SIZE
+ Size of 'early' trace buffer. Before U-Boot has relocated
+ it doesn't have a proper trace buffer. On many boards
+ you can define an area of memory to use for the trace
+ buffer until the 'real' trace buffer is available after
+ relocation. The contents of this buffer are then copied to
+ the real buffer.
+
+- CONFIG_TRACE_EARLY_ADDR
+ Address of early trace buffer
+
+
+Building U-Boot with Tracing Enabled
+------------------------------------
+
+Pass 'FTRACE=1' to the U-Boot Makefile to actually instrument the code.
+This is kept as a separate option so that it is easy to enable/disable
+instrumenting from the command line instead of having to change board
+config files.
+
+
+Collecting Trace Data
+---------------------
+
+When you run U-Boot on your board it will collect trace data up to the
+limit of the trace buffer size you have specified. Once that is exhausted
+no more data will be collected.
+
+Collecting trace data has an affect on execution time/performance. You
+will notice this particularly with trvial functions - the overhead of
+recording their execution may even exceed their normal execution time.
+In practice this doesn't matter much so long as you are aware of the
+effect. Once you have done your optimisations, turn off tracing before
+doing end-to-end timing.
+
+The best time to start tracing is right at the beginning of U-Boot. The
+best time to stop tracing is right at the end. In practice it is hard
+to achieve these ideals.
+
+This implementation enables tracing early in board_init_f(). This means
+that it captures most of the board init process, missing only the
+early architecture-specific init. However, it also misses the entire
+SPL stage if there is one.
+
+U-Boot typically ends with a 'bootm' command which loads and runs an
+OS. There is useful trace data in the execution of that bootm
+command. Therefore this implementation provides a way to collect trace
+data after bootm has finished processing, but just before it jumps to
+the OS. In practical terms, U-Boot runs the 'fakegocmd' environment
+variable at this point. This variable should have a short script which
+collects the trace data and writes it somewhere.
+
+Trace data collection relies on a microsecond timer, accesed through
+timer_get_us(). So the first think you should do is make sure that
+this produces sensible results for your board. Suitable sources for
+this timer include high resolution timers, PWMs or profile timers if
+available. Most modern SOCs have a suitable timer for this. Make sure
+that you mark this timer (and anything it calls) with
+__attribute__((no_instrument_function)) so that the trace library can
+use it without causing an infinite loop.
+
+
+Commands
+--------
+
+The trace command has variable sub-commands:
+
+- stats
+ Display tracing statistics
+
+- pause
+ Pause tracing
+
+- resume
+ Resume tracing
+
+- funclist [<addr> <size>]
+ Dump a list of functions into the buffer
+
+- calls [<addr> <size>]
+ Dump function call trace into buffer
+
+If the address and size are not given, these are obtained from environment
+variables (see below). In any case the environment variables are updated
+after the command runs.
+
+
+Environment Variables
+---------------------
+
+The following are used:
+
+- profbase
+ Base address of trace output buffer
+
+- profoffset
+ Offset of first unwritten byte in trace output buffer
+
+- profsize
+ Size of trace output buffer
+
+All of these are set by the 'trace calls' command.
+
+These variables keep track of the amount of data written to the trace
+output buffer by the 'trace' command. The trace commands which write data
+to the output buffer can use these to specify the buffer to write to, and
+update profoffset each time. This allows successive commands to append data
+to the same buffer, for example:
+
+ trace funclist 10000 e00000
+ trace calls
+
+(the latter command appends more data to the buffer).
+
+
+- fakegocmd
+ Specifies commands to run just before booting the OS. This
+ is a useful time to write the trace data to the host for
+ processing.
+
+
+Writing Out Trace Data
+----------------------
+
+Once the trace data is in an output buffer in memory there are various ways
+to transmit it to the host. Notably you can use tftput to send the data
+over a network link:
+
+fakegocmd=trace pause; usb start; set autoload n; bootp;
+ trace calls 10000000 1000000;
+ tftpput ${profbase} ${profoffset} 192.168.1.4:/tftpboot/calls
+
+This starts up USB (to talk to an attached USB Ethernet dongle), writes
+a trace log to address 10000000 and sends it to a host machine using
+TFTP. After this, U-Boot will boot the OS normally, albeit a little
+later.
+
+
+Converting Trace Output Data
+----------------------------
+
+The trace output data is kept in a binary format which is not documented
+here. To convert it into something useful, you can use proftool.
+
+This tool must be given the U-Boot map file and the trace data received
+from running that U-Boot. It produces a text output file.
+
+Options
+ -m <map_file>
+ Specify U-Boot map file
+
+ -p <trace_file>
+ Specifiy profile/trace file
+
+Commands:
+
+- dump-ftrace
+ Write a text dump of the file in Linux ftrace format to stdout
+
+
+Viewing the Trace Data
+----------------------
+
+You can use pytimechart for this (sudo apt-get pytimechart might work on
+your Debian-style machine, and use your favourite search engine to obtain
+documentation). It expects the file to have a .txt extension. The program
+has terse user interface but is very convenient for viewing U-Boot
+profile information.
+
+
+Workflow Suggestions
+--------------------
+
+The following suggestions may be helpful if you are trying to reduce boot
+time:
+
+1. Enable CONFIG_BOOTSTAGE and CONFIG_BOOTSTAGE_REPORT. This should get
+you are helpful overall snapshot of the boot time.
+
+2. Build U-Boot with tracing and run it. Note the difference in boot time
+(it is common for tracing to add 10% to the time)
+
+3. Collect the trace information as descibed above. Use this to find where
+all the time is being spent.
+
+4. Take a look at that code and see if you can optimise it. Perhaps it is
+possible to speed up the initialisation of a device, or remove an unused
+feature.
+
+5. Rebuild, run and collect again. Compare your results.
+
+6. Keep going until you run out of steam, or your boot is fast enough.
+
+
+Configuring Trace
+-----------------
+
+There are a few parameters in the code that you may want to consider.
+There is a function call depth limit (set to 15 by default). When the
+stack depth goes above this then no tracing information is recorded.
+The maximum depth reached is recorded and displayed by the 'trace stats'
+command.
+
+
+Future Work
+-----------
+
+Tracing could be a little tidier in some areas, for example providing
+run-time configuration options for trace.
+
+Some other features that might be useful:
+
+- Trace filter to select which functions are recorded
+- Sample-based profiling using a timer interrupt
+- Better control over trace depth
+- Compression of trace information
+
+
+Simon Glass <sjg@chromium.org>
+April 2013
diff --git a/doc/device-tree-bindings/input/cros-ec-keyb.txt b/doc/device-tree-bindings/input/cros-ec-keyb.txt
new file mode 100644
index 0000000..3118276
--- /dev/null
+++ b/doc/device-tree-bindings/input/cros-ec-keyb.txt
@@ -0,0 +1,79 @@
+CROS_EC Keyboard
+
+The CROS_EC (Matrix Keyboard Protocol) allows communcation with a secondary
+micro used for keyboard, and possible other features.
+
+The CROS_EC keyboard uses this protocol to receive key scans and produce input
+in U-Boot.
+
+Required properties :
+- compatible : "google,cros-ec-keyb"
+- google,key-rows : Number of key rows
+- google,key-columns : Number of key columns
+
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+
+- linux,fn-keymap: a second keymap, same specification as the
+ matrix-keyboard-controller spec but to be used when the KEY_FN modifier
+ key is pressed.
+- google,repeat-delay-ms : delay in milliseconds before repeat starts
+- google,repeat-rate-ms : delay between each subsequent key press
+- google,ghost-filter : enable ghost filtering for this device
+
+Example, taken from daisy:
+
+cros-ec-keyb {
+ compatible = "google,cros-ec-keyb";
+ google,key-rows = <8>;
+ google,key-columns = <13>;
+ google,ghost-filter;
+ google,repeat-delay-ms = <240>;
+ google,repeat-rate-ms = <30>;
+ /*
+ * Keymap entries take the form of 0xRRCCKKKK where
+ * RR=Row CC=Column KKKK=Key Code
+ * The values below are for a US keyboard layout and
+ * are taken from the Linux driver. Note that the
+ * 102ND key is not used for US keyboards.
+ */
+ linux,keymap = <
+ /* CAPSLCK F1 B F10 */
+ 0x0001003a 0x0002003c 0x00030030 0x00040044
+ /* N = R_ALT ESC */
+ 0x00060031 0x0008000d 0x000a0064 0x01010001
+ /* F4 G F7 H */
+ 0x0102003e 0x01030022 0x01040041 0x01060023
+ /* ' F9 BKSPACE L_CTRL */
+ 0x01080028 0x01090043 0x010b000e 0x0200001d
+ /* TAB F3 T F6 */
+ 0x0201000f 0x0202003d 0x02030014 0x02040040
+ /* ] Y 102ND [ */
+ 0x0205001b 0x02060015 0x02070056 0x0208001a
+ /* F8 GRAVE F2 5 */
+ 0x02090042 0x03010029 0x0302003c 0x03030006
+ /* F5 6 - \ */
+ 0x0304003f 0x03060007 0x0308000c 0x030b002b
+ /* R_CTRL A D F */
+ 0x04000061 0x0401001e 0x04020020 0x04030021
+ /* S K J ; */
+ 0x0404001f 0x04050025 0x04060024 0x04080027
+ /* L ENTER Z C */
+ 0x04090026 0x040b001c 0x0501002c 0x0502002e
+ /* V X , M */
+ 0x0503002f 0x0504002d 0x05050033 0x05060032
+ /* L_SHIFT / . SPACE */
+ 0x0507002a 0x05080035 0x05090034 0x050B0039
+ /* 1 3 4 2 */
+ 0x06010002 0x06020004 0x06030005 0x06040003
+ /* 8 7 0 9 */
+ 0x06050009 0x06060008 0x0608000b 0x0609000a
+ /* L_ALT DOWN RIGHT Q */
+ 0x060a0038 0x060b006c 0x060c006a 0x07010010
+ /* E R W I */
+ 0x07020012 0x07030013 0x07040011 0x07050017
+ /* U R_SHIFT P O */
+ 0x07060016 0x07070036 0x07080019 0x07090018
+ /* UP LEFT */
+ 0x070b0067 0x070c0069>;
+};
diff --git a/doc/device-tree-bindings/misc/cros-ec.txt b/doc/device-tree-bindings/misc/cros-ec.txt
new file mode 100644
index 0000000..07ea7cd
--- /dev/null
+++ b/doc/device-tree-bindings/misc/cros-ec.txt
@@ -0,0 +1,38 @@
+Chrome OS CROS_EC Binding
+======================
+
+The device tree node which describes the operation of the CROS_EC interface
+is as follows:
+
+Required properties :
+- compatible = "google,cros-ec"
+
+Optional properties :
+- spi-max-frequency : Sets the maximum frequency (in Hz) for SPI bus
+ operation
+- i2c-max-frequency : Sets the maximum frequency (in Hz) for I2C bus
+ operation
+- ec-interrupt : Selects the EC interrupt, defined as a GPIO according
+ to the platform
+- optimise-flash-write : Boolean property - if present then flash blocks
+ containing all 0xff will not be written, since we assume that the EC
+ uses that pattern for erased blocks
+
+The CROS_EC node should appear as a subnode of the interrupt that connects it
+to the EC (e.g. i2c, spi, lpc). The reg property (as usual) will indicate
+the unit address on that bus.
+
+
+Example
+=======
+
+ spi@131b0000 {
+ cros-ec@0 {
+ reg = <0>;
+ compatible = "google,cros-ec";
+ spi-max-frequency = <5000000>;
+ ec-interrupt = <&gpio 174 1>;
+ optimise-flash-write;
+ status = "disabled";
+ };
+ };
diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 39652c8..14374da 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -4,7 +4,17 @@
mkimage \- Generate image for U-Boot
.SH SYNOPSIS
.B mkimage
-.RB [\fIoptions\fP]
+.RB "\-l [" "uimage file name" "]"
+
+.B mkimage
+.RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]"
+
+.B mkimage
+.RB [\fIoptions\fP] " \-F [" "uimage file name" "]"
+
+.B mkimage
+.RB [\fIoptions\fP] " (legacy mode)"
+
.SH "DESCRIPTION"
The
.B mkimage
@@ -26,7 +36,8 @@ etc.
The new
.I FIT (Flattened Image Tree) format
allows for more flexibility in handling images of various types and also
-enhances integrity protection of images with stronger checksums.
+enhances integrity protection of images with stronger checksums. It also
+supports verified boot.
.SH "OPTIONS"
@@ -67,6 +78,10 @@ Set load address with a hex number.
Set entry point with a hex number.
.TP
+.BI "\-l"
+List the contents of an image.
+
+.TP
.BI "\-n [" "image name" "]"
Set image name to 'image name'.
@@ -82,6 +97,12 @@ Set XIP (execute in place) flag.
.B Create FIT image:
.TP
+.BI "\-c [" "comment" "]"
+Specifies a comment to be added when signing. This is typically a useful
+message which describes how the image was signed or some other useful
+information.
+
+.TP
.BI "\-D [" "dtc options" "]"
Provide special options to the device tree compiler that is used to
create the image.
@@ -91,6 +112,33 @@ create the image.
Image tree source file that describes the structure and contents of the
FIT image.
+.TP
+.BI "\-F"
+Indicates that an existing FIT image should be modified. No dtc
+compilation is performed and the -f flag should not be given.
+This can be used to sign images with additional keys after initial image
+creation.
+
+.TP
+.BI "\-k [" "key_directory" "]"
+Specifies the directory containing keys to use for signing. This directory
+should contain a private key file <name>.key for use with signing and a
+certificate <name>.crt (containing the public key) for use with verification.
+
+.TP
+.BI "\-K [" "key_destination" "]"
+Specifies a compiled device tree binary file (typically .dtb) to write
+public key information into. When a private key is used to sign an image,
+the corresponding public key is written into this file for for run-time
+verification. Typically the file here is the device tree binary used by
+CONFIG_OF_CONTROL in U-Boot.
+
+.TP
+.BI "\-r
+Specifies that keys used to sign the FIT are required. This means that they
+must be verified for the image to boot. Without this option, the verification
+will be optional (useful for testing but not for release).
+
.SH EXAMPLES
List image information:
@@ -109,10 +157,29 @@ Create FIT image with compressed PowerPC Linux kernel:
.nf
.B mkimage -f kernel.its kernel.itb
.fi
+.P
+Create FIT image with compressed kernel and sign it with keys in the
+/public/signing-keys directory. Add corresponding public keys into u-boot.dtb,
+skipping those for which keys cannot be found. Also add a comment.
+.nf
+.B mkimage -f kernel.its -k /public/signing-keys -K u-boot.dtb \\\\
+-c "Kernel 3.8 image for production devices" kernel.itb
+.fi
+
+.P
+Update an existing FIT image, signing it with additional keys.
+Add corresponding public keys into u-boot.dtb. This will resign all images
+with keys that are available in the new directory. Images that request signing
+with unavailable keys are skipped.
+.nf
+.B mkimage -F -k /secret/signing-keys -K u-boot.dtb \\\\
+-c "Kernel 3.8 image for production devices" kernel.itb
+.fi
.SH HOMEPAGE
http://www.denx.de/wiki/U-Boot/WebHome
.PP
.SH AUTHOR
This manual page was written by Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
-and Wolfgang Denk <wd@denx.de>
+and Wolfgang Denk <wd@denx.de>. It was updated for image signing by
+Simon Glass <sjg@chromium.org>.
diff --git a/doc/uImage.FIT/sign-configs.its b/doc/uImage.FIT/sign-configs.its
new file mode 100644
index 0000000..3c17f04
--- /dev/null
+++ b/doc/uImage.FIT/sign-configs.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "lzo";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ hash@1 {
+ algo = "sha1";
+ };
+ };
+ fdt@1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ hash@1 {
+ algo = "sha1";
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ sign-images = "fdt", "kernel";
+ };
+ };
+ };
+};
diff --git a/doc/uImage.FIT/sign-images.its b/doc/uImage.FIT/sign-images.its
new file mode 100644
index 0000000..f69326a
--- /dev/null
+++ b/doc/uImage.FIT/sign-images.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ };
+ };
+ fdt@1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ };
+ };
+};
diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt
new file mode 100644
index 0000000..bc9f3fa
--- /dev/null
+++ b/doc/uImage.FIT/signature.txt
@@ -0,0 +1,382 @@
+U-Boot FIT Signature Verification
+=================================
+
+Introduction
+------------
+FIT supports hashing of images so that these hashes can be checked on
+loading. This protects against corruption of the image. However it does not
+prevent the substitution of one image for another.
+
+The signature feature allows the hash to be signed with a private key such
+that it can be verified using a public key later. Provided that the private
+key is kept secret and the public key is stored in a non-volatile place,
+any image can be verified in this way.
+
+See verified-boot.txt for more general information on verified boot.
+
+
+Concepts
+--------
+Some familiarity with public key cryptography is assumed in this section.
+
+The procedure for signing is as follows:
+
+ - hash an image in the FIT
+ - sign the hash with a private key to produce a signature
+ - store the resulting signature in the FIT
+
+The procedure for verification is:
+
+ - read the FIT
+ - obtain the public key
+ - extract the signature from the FIT
+ - hash the image from the FIT
+ - verify (with the public key) that the extracted signature matches the
+ hash
+
+The signing is generally performed by mkimage, as part of making a firmware
+image for the device. The verification is normally done in U-Boot on the
+device.
+
+
+Algorithms
+----------
+In principle any suitable algorithm can be used to sign and verify a hash.
+At present only one class of algorithms is supported: SHA1 hashing with RSA.
+This works by hashing the image to produce a 20-byte hash.
+
+While it is acceptable to bring in large cryptographic libraries such as
+openssl on the host side (e.g. mkimage), it is not desirable for U-Boot.
+For the run-time verification side, it is important to keep code and data
+size as small as possible.
+
+For this reason the RSA image verification uses pre-processed public keys
+which can be used with a very small amount of code - just some extraction
+of data from the FDT and exponentiation mod n. Code size impact is a little
+under 5KB on Tegra Seaboard, for example.
+
+It is relatively straightforward to add new algorithms if required. If
+another RSA variant is needed, then it can be added to the table in
+image-sig.c. If another algorithm is needed (such as DSA) then it can be
+placed alongside rsa.c, and its functions added to the table in image-sig.c
+also.
+
+
+Creating an RSA key and certificate
+-----------------------------------
+To create a new public key, size 2048 bits:
+
+$ openssl genrsa -F4 -out keys/dev.key 2048
+
+To create a certificate for this:
+
+$ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt
+
+If you like you can look at the public key also:
+
+$ openssl rsa -in keys/dev.key -pubout
+
+
+Device Tree Bindings
+--------------------
+The following properties are required in the FIT's signature node(s) to
+allow thes signer to operate. These should be added to the .its file.
+Signature nodes sit at the same level as hash nodes and are called
+signature@1, signature@2, etc.
+
+- algo: Algorithm name (e.g. "sha1,rs2048")
+
+- key-name-hint: Name of key to use for signing. The keys will normally be in
+a single directory (parameter -k to mkimage). For a given key <name>, its
+private key is stored in <name>.key and the certificate is stored in
+<name>.crt.
+
+When the image is signed, the following properties are added (mandatory):
+
+- value: The signature data (e.g. 256 bytes for 2048-bit RSA)
+
+When the image is signed, the following properties are optional:
+
+- timestamp: Time when image was signed (standard Unix time_t format)
+
+- signer-name: Name of the signer (e.g. "mkimage")
+
+- signer-version: Version string of the signer (e.g. "2013.01")
+
+- comment: Additional information about the signer or image
+
+For config bindings (see Signed Configurations below), the following
+additional properties are optional:
+
+- sign-images: A list of images to sign, each being a property of the conf
+node that contains then. The default is "kernel,fdt" which means that these
+two images will be looked up in the config and signed if present.
+
+For config bindings, these properties are added by the signer:
+
+- hashed-nodes: A list of nodes which were hashed by the signer. Each is
+ a string - the full path to node. A typical value might be:
+
+ hashed-nodes = "/", "/configurations/conf@1", "/images/kernel@1",
+ "/images/kernel@1/hash@1", "/images/fdt@1",
+ "/images/fdt@1/hash@1";
+
+- hashed-strings: The start and size of the string region of the FIT that
+ was hashed
+
+Example: See sign-images.its for an example image tree source file and
+sign-configs.its for config signing.
+
+
+Public Key Storage
+------------------
+In order to verify an image that has been signed with a public key we need to
+have a trusted public key. This cannot be stored in the signed image, since
+it would be easy to alter. For this implementation we choose to store the
+public key in U-Boot's control FDT (using CONFIG_OF_CONTROL).
+
+Public keys should be stored as sub-nodes in a /signature node. Required
+properties are:
+
+- algo: Algorithm name (e.g. "sha1,rs2048")
+
+Optional properties are:
+
+- key-name-hint: Name of key used for signing. This is only a hint since it
+is possible for the name to be changed. Verification can proceed by checking
+all available signing keys until one matches.
+
+- required: If present this indicates that the key must be verified for the
+image / configuration to be considered valid. Only required keys are
+normally verified by the FIT image booting algorithm. Valid values are
+"image" to force verification of all images, and "conf" to force verfication
+of the selected configuration (which then relies on hashes in the images to
+verify those).
+
+Each signing algorithm has its own additional properties.
+
+For RSA the following are mandatory:
+
+- rsa,num-bits: Number of key bits (e.g. 2048)
+- rsa,modulus: Modulus (N) as a big-endian multi-word integer
+- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer
+- rsa,n0-inverse: -1 / modulus[0] mod 2^32
+
+
+Signed Configurations
+---------------------
+While signing images is useful, it does not provide complete protection
+against several types of attack. For example, it it possible to create a
+FIT with the same signed images, but with the configuration changed such
+that a different one is selected (mix and match attack). It is also possible
+to substitute a signed image from an older FIT version into a newer FIT
+(roll-back attack).
+
+As an example, consider this FIT:
+
+/ {
+ images {
+ kernel@1 {
+ data = <data for kernel1>
+ signature@1 {
+ algo = "sha1,rsa2048";
+ value = <...kernel signature 1...>
+ };
+ };
+ kernel@2 {
+ data = <data for kernel2>
+ signature@1 {
+ algo = "sha1,rsa2048";
+ value = <...kernel signature 2...>
+ };
+ };
+ fdt@1 {
+ data = <data for fdt1>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ vaue = <...fdt signature 1...>
+ };
+ };
+ fdt@2 {
+ data = <data for fdt2>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ vaue = <...fdt signature 2...>
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ };
+ conf@1 {
+ kernel = "kernel@2";
+ fdt = "fdt@2";
+ };
+ };
+};
+
+Since both kernels are signed it is easy for an attacker to add a new
+configuration 3 with kernel 1 and fdt 2:
+
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ };
+ conf@1 {
+ kernel = "kernel@2";
+ fdt = "fdt@2";
+ };
+ conf@3 {
+ kernel = "kernel@1";
+ fdt = "fdt@2";
+ };
+ };
+
+With signed images, nothing protects against this. Whether it gains an
+advantage for the attacker is debatable, but it is not secure.
+
+To solved this problem, we support signed configurations. In this case it
+is the configurations that are signed, not the image. Each image has its
+own hash, and we include the hash in the configuration signature.
+
+So the above example is adjusted to look like this:
+
+/ {
+ images {
+ kernel@1 {
+ data = <data for kernel1>
+ hash@1 {
+ algo = "sha1";
+ value = <...kernel hash 1...>
+ };
+ };
+ kernel@2 {
+ data = <data for kernel2>
+ hash@1 {
+ algo = "sha1";
+ value = <...kernel hash 2...>
+ };
+ };
+ fdt@1 {
+ data = <data for fdt1>;
+ hash@1 {
+ algo = "sha1";
+ value = <...fdt hash 1...>
+ };
+ };
+ fdt@2 {
+ data = <data for fdt2>;
+ hash@1 {
+ algo = "sha1";
+ value = <...fdt hash 2...>
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ signature@1 {
+ algo = "sha1,rsa2048";
+ value = <...conf 1 signature...>;
+ };
+ };
+ conf@2 {
+ kernel = "kernel@2";
+ fdt = "fdt@2";
+ signature@1 {
+ algo = "sha1,rsa2048";
+ value = <...conf 1 signature...>;
+ };
+ };
+ };
+};
+
+
+You can see that we have added hashes for all images (since they are no
+longer signed), and a signature to each configuration. In the above example,
+mkimage will sign configurations/conf@1, the kernel and fdt that are
+pointed to by the configuration (/images/kernel@1, /images/kernel@1/hash@1,
+/images/fdt@1, /images/fdt@1/hash@1) and the root structure of the image
+(so that it isn't possible to add or remove root nodes). The signature is
+written into /configurations/conf@1/signature@1/value. It can easily be
+verified later even if the FIT has been signed with other keys in the
+meantime.
+
+
+Verification
+------------
+FITs are verified when loaded. After the configuration is selected a list
+of required images is produced. If there are 'required' public keys, then
+each image must be verified against those keys. This means that every image
+that might be used by the target needs to be signed with 'required' keys.
+
+This happens automatically as part of a bootm command when FITs are used.
+
+
+Enabling FIT Verification
+-------------------------
+In addition to the options to enable FIT itself, the following CONFIGs must
+be enabled:
+
+CONFIG_FIT_SIGNATURE - enable signing and verfication in FITs
+CONFIG_RSA - enable RSA algorithm for signing
+
+
+Testing
+-------
+An easy way to test signing and verfication is to use the test script
+provided in test/vboot/vboot_test.sh. This uses sandbox (a special version
+of U-Boot which runs under Linux) to show the operation of a 'bootm'
+command loading and verifying images.
+
+A sample run is show below:
+
+$ make O=sandbox sandbox_config
+$ make O=sandbox
+$ O=sandbox ./test/vboot/vboot_test.sh
+Simple Verified Boot Test
+=========================
+
+Please see doc/uImage.FIT/verified-boot.txt for more information
+
+Build keys
+Build FIT with signed images
+Test Verified Boot Run: unsigned signatures:: OK
+Sign images
+Test Verified Boot Run: signed images: OK
+Build FIT with signed configuration
+Test Verified Boot Run: unsigned config: OK
+Sign images
+Test Verified Boot Run: signed config: OK
+
+Test passed
+
+
+Future Work
+-----------
+- Roll-back protection using a TPM is done using the tpm command. This can
+be scripted, but we might consider a default way of doing this, built into
+bootm.
+
+
+Possible Future Work
+--------------------
+- Add support for other RSA/SHA variants, such as rsa4096,sha512.
+- Other algorithms besides RSA
+- More sandbox tests for failure modes
+- Passwords for keys/certificates
+- Perhaps implement OAEP
+- Enhance bootm to permit scripted signature verification (so that a script
+can verify an image but not actually boot it)
+
+
+Simon Glass
+sjg@chromium.org
+1-1-13
diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt
new file mode 100644
index 0000000..3c83fbc
--- /dev/null
+++ b/doc/uImage.FIT/verified-boot.txt
@@ -0,0 +1,104 @@
+U-Boot Verified Boot
+====================
+
+Introduction
+------------
+Verified boot here means the verification of all software loaded into a
+machine during the boot process to ensure that it is authorised and correct
+for that machine.
+
+Verified boot extends from the moment of system reset to as far as you wish
+into the boot process. An example might be loading U-Boot from read-only
+memory, then loading a signed kernel, then using the kernel's dm-verity
+driver to mount a signed root filesystem.
+
+A key point is that it is possible to field-upgrade the software on machines
+which use verified boot. Since the machine will only run software that has
+been correctly signed, it is safe to read software from an updatable medium.
+It is also possible to add a secondary signed firmware image, in read-write
+memory, so that firmware can easily be upgraded in a secure manner.
+
+
+Signing
+-------
+Verified boot uses cryptographic algorithms to 'sign' software images.
+Images are signed using a private key known only to the signer, but can
+be verified using a public key. As its name suggests the public key can be
+made available without risk to the verification process. The private and
+public keys are mathematically related. For more information on how this
+works look up "public key cryptography" and "RSA" (a particular algorithm).
+
+The signing and verification process looks something like this:
+
+
+ Signing Verification
+ ======= ============
+
+ +--------------+ *
+ | RSA key pair | * +---------------+
+ | .key .crt | * | Public key in |
+ +--------------+ +------> public key ----->| trusted place |
+ | | * +---------------+
+ | | * |
+ v | * v
+ +---------+ | * +--------------+
+ | |----------+ * | |
+ | signer | * | U-Boot |
+ | |----------+ * | signature |--> yes/no
+ +---------+ | * | verification |
+ ^ | * | |
+ | | * +--------------+
+ | | * ^
+ +----------+ | * |
+ | Software | +----> signed image -------------+
+ | image | *
+ +----------+ *
+
+
+The signature algorithm relies only on the public key to do its work. Using
+this key it checks the signature that it finds in the image. If it verifies
+then we know that the image is OK.
+
+The public key from the signer allows us to verify and therefore trust
+software from updatable memory.
+
+It is critical that the public key be secure and cannot be tampered with.
+It can be stored in read-only memory, or perhaps protected by other on-chip
+crypto provided by some modern SOCs. If the public key can ben changed, then
+the verification is worthless.
+
+
+Chaining Images
+---------------
+The above method works for a signer providing images to a run-time U-Boot.
+It is also possible to extend this scheme to a second level, like this:
+
+1. Master private key is used by the signer to sign a first-stage image.
+2. Master public key is placed in read-only memory.
+2. Secondary private key is created and used to sign second-stage images.
+3. Secondary public key is placed in first stage images
+4. We use the master public key to verify the first-stage image. We then
+use the secondary public key in the first-stage image to verify the second-
+state image.
+5. This chaining process can go on indefinitely. It is recommended to use a
+different key at each stage, so that a compromise in one place will not
+affect the whole change.
+
+
+Flattened Image Tree (FIT)
+--------------------------
+The FIT format is alreay widely used in U-Boot. It is a flattened device
+tree (FDT) in a particular format, with images contained within. FITs
+include hashes to verify images, so it is relatively straightforward to
+add signatures as well.
+
+The public key can be stored in U-Boot's CONFIG_OF_CONTROL device tree in
+a standard place. Then when a FIT it loaded it can be verified using that
+public key. Multiple keys and multiple signatures are supported.
+
+See signature.txt for more information.
+
+
+Simon Glass
+sjg@chromium.org
+1-1-13
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index f3adf64..bb8e644 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -133,8 +133,7 @@ int dtt_init_one(int sensor)
/*
* Setup PWM Lookup-Table
*/
- for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry);
- i++) {
+ for (i = 0; i < ARRAY_SIZE(pwm_lookup); i++) {
int address = DTT_PWM_LOOKUP_BASE + 2 * i;
val = pwm_lookup[i].temp;
if (is_lm64(sensor))
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 0805e86..4331190 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -27,6 +27,7 @@ LIB := $(obj)libinput.o
COBJS-$(CONFIG_I8042_KBD) += i8042.o
COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o
+COBJS-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o
ifdef CONFIG_PS2KBD
COBJS-y += keyboard.o pc_keyb.o
COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c
new file mode 100644
index 0000000..c197308
--- /dev/null
+++ b/drivers/input/cros_ec_keyb.c
@@ -0,0 +1,261 @@
+/*
+ * Chromium OS Matrix Keyboard
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <fdtdec.h>
+#include <input.h>
+#include <key_matrix.h>
+#include <stdio_dev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+ KBC_MAX_KEYS = 8, /* Maximum keys held down at once */
+};
+
+static struct keyb {
+ struct cros_ec_dev *dev; /* The CROS_EC device */
+ struct input_config input; /* The input layer */
+ struct key_matrix matrix; /* The key matrix layer */
+ int key_rows; /* Number of keyboard rows */
+ int key_cols; /* Number of keyboard columns */
+ unsigned int repeat_delay_ms; /* Time before autorepeat starts */
+ unsigned int repeat_rate_ms; /* Autorepeat rate in ms */
+ int ghost_filter; /* 1 to enable ghost filter, else 0 */
+ int inited; /* 1 if keyboard is ready */
+} config;
+
+
+/**
+ * Check the keyboard controller and return a list of key matrix positions
+ * for which a key is pressed
+ *
+ * @param config Keyboard config
+ * @param keys List of keys that we have detected
+ * @param max_count Maximum number of keys to return
+ * @return number of pressed keys, 0 for none
+ */
+static int check_for_keys(struct keyb *config,
+ struct key_matrix_key *keys, int max_count)
+{
+ struct key_matrix_key *key;
+ struct mbkp_keyscan scan;
+ unsigned int row, col, bit, data;
+ int num_keys;
+
+ if (cros_ec_scan_keyboard(config->dev, &scan)) {
+ debug("%s: keyboard scan failed\n", __func__);
+ return -1;
+ }
+
+ for (col = num_keys = bit = 0; col < config->matrix.num_cols;
+ col++) {
+ for (row = 0; row < config->matrix.num_rows; row++) {
+ unsigned int mask = 1 << (bit & 7);
+
+ data = scan.data[bit / 8];
+ if ((data & mask) && num_keys < max_count) {
+ key = keys + num_keys++;
+ key->row = row;
+ key->col = col;
+ key->valid = 1;
+ }
+ bit++;
+ }
+ }
+
+ return num_keys;
+}
+
+/**
+ * Test if keys are available to be read
+ *
+ * @return 0 if no keys available, 1 if keys are available
+ */
+static int kbd_tstc(void)
+{
+ /* Just get input to do this for us */
+ return config.inited ? input_tstc(&config.input) : 0;
+}
+
+/**
+ * Read a key
+ *
+ * @return ASCII key code, or 0 if no key, or -1 if error
+ */
+static int kbd_getc(void)
+{
+ /* Just get input to do this for us */
+ return config.inited ? input_getc(&config.input) : 0;
+}
+
+/**
+ * Check the keyboard, and send any keys that are pressed.
+ *
+ * This is called by input_tstc() and input_getc() when they need more
+ * characters
+ *
+ * @param input Input configuration
+ * @return 1, to indicate that we have something to look at
+ */
+int cros_ec_kbc_check(struct input_config *input)
+{
+ static struct key_matrix_key last_keys[KBC_MAX_KEYS];
+ static int last_num_keys;
+ struct key_matrix_key keys[KBC_MAX_KEYS];
+ int keycodes[KBC_MAX_KEYS];
+ int num_keys, num_keycodes;
+ int irq_pending, sent;
+
+ /*
+ * Loop until the EC has no more keyscan records, or we have
+ * received at least one character. This means we know that tstc()
+ * will always return non-zero if keys have been pressed.
+ *
+ * Without this loop, a key release (which generates no new ascii
+ * characters) will cause us to exit this function, and just tstc()
+ * may return 0 before all keys have been read from the EC.
+ */
+ do {
+ irq_pending = cros_ec_interrupt_pending(config.dev);
+ if (irq_pending) {
+ num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS);
+ last_num_keys = num_keys;
+ memcpy(last_keys, keys, sizeof(keys));
+ } else {
+ /*
+ * EC doesn't want to be asked, so use keys from last
+ * time.
+ */
+ num_keys = last_num_keys;
+ memcpy(keys, last_keys, sizeof(keys));
+ }
+
+ if (num_keys < 0)
+ return -1;
+ num_keycodes = key_matrix_decode(&config.matrix, keys,
+ num_keys, keycodes, KBC_MAX_KEYS);
+ sent = input_send_keycodes(input, keycodes, num_keycodes);
+ } while (irq_pending && !sent);
+
+ return 1;
+}
+
+/**
+ * Decode MBKP keyboard details from the device tree
+ *
+ * @param blob Device tree blob
+ * @param node Node to decode from
+ * @param config Configuration data read from fdt
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_keyb_decode_fdt(const void *blob, int node,
+ struct keyb *config)
+{
+ /*
+ * Get keyboard rows and columns - at present we are limited to
+ * 8 columns by the protocol (one byte per row scan)
+ */
+ config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0);
+ config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", 0);
+ if (!config->key_rows || !config->key_cols ||
+ config->key_rows * config->key_cols / 8
+ > CROS_EC_KEYSCAN_COLS) {
+ debug("%s: Invalid key matrix size %d x %d\n", __func__,
+ config->key_rows, config->key_cols);
+ return -1;
+ }
+ config->repeat_delay_ms = fdtdec_get_int(blob, node,
+ "google,repeat-delay-ms", 0);
+ config->repeat_rate_ms = fdtdec_get_int(blob, node,
+ "google,repeat-rate-ms", 0);
+ config->ghost_filter = fdtdec_get_bool(blob, node,
+ "google,ghost-filter");
+ return 0;
+}
+
+/**
+ * Set up the keyboard. This is called by the stdio device handler.
+ *
+ * We want to do this init when the keyboard is actually used rather than
+ * at start-up, since keyboard input may not currently be selected.
+ *
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_init_keyboard(void)
+{
+ const void *blob = gd->fdt_blob;
+ int node;
+
+ config.dev = board_get_cros_ec_dev();
+ if (!config.dev) {
+ debug("%s: no cros_ec device: cannot init keyboard\n",
+ __func__);
+ return -1;
+ }
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+ if (node < 0) {
+ debug("%s: Node not found\n", __func__);
+ return -1;
+ }
+ if (cros_ec_keyb_decode_fdt(blob, node, &config))
+ return -1;
+ input_set_delays(&config.input, config.repeat_delay_ms,
+ config.repeat_rate_ms);
+ if (key_matrix_init(&config.matrix, config.key_rows,
+ config.key_cols, config.ghost_filter)) {
+ debug("%s: cannot init key matrix\n", __func__);
+ return -1;
+ }
+ if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) {
+ debug("%s: Could not decode key matrix from fdt\n", __func__);
+ return -1;
+ }
+ config.inited = 1;
+ debug("%s: Matrix keyboard %dx%d ready\n", __func__, config.key_rows,
+ config.key_cols);
+
+ return 0;
+}
+
+int drv_keyboard_init(void)
+{
+ struct stdio_dev dev;
+
+ if (input_init(&config.input, 0)) {
+ debug("%s: Cannot set up input\n", __func__);
+ return -1;
+ }
+ config.input.read_keys = cros_ec_kbc_check;
+
+ memset(&dev, '\0', sizeof(dev));
+ strcpy(dev.name, "cros-ec-keyb");
+ dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ dev.getc = kbd_getc;
+ dev.tstc = kbd_tstc;
+ dev.start = cros_ec_init_keyboard;
+
+ /* Register the device. cros_ec_init_keyboard() will be called soon */
+ return input_stdio_register(&dev);
+}
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5d869b4..5fbff8a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -28,6 +28,10 @@ LIB := $(obj)libmisc.o
COBJS-$(CONFIG_ALI152X) += ali512x.o
COBJS-$(CONFIG_DS4510) += ds4510.o
COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
+COBJS-$(CONFIG_CROS_EC) += cros_ec.o
+COBJS-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
+COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
+COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o
COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
new file mode 100644
index 0000000..6e774d9
--- /dev/null
+++ b/drivers/misc/cros_ec.c
@@ -0,0 +1,1304 @@
+/*
+ * Chromium OS cros_ec driver
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <cros_ec.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+enum {
+ /* Timeout waiting for a flash erase command to complete */
+ CROS_EC_CMD_TIMEOUT_MS = 5000,
+ /* Timeout waiting for a synchronous hash to be recomputed */
+ CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
+};
+
+static struct cros_ec_dev static_dev, *last_dev;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Note: depends on enum ec_current_image */
+static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
+
+void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
+{
+#ifdef DEBUG
+ int i;
+
+ printf("%s: ", name);
+ if (cmd != -1)
+ printf("cmd=%#x: ", cmd);
+ for (i = 0; i < len; i++)
+ printf("%02x ", data[i]);
+ printf("\n");
+#endif
+}
+
+/*
+ * Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data Data block to checksum
+ * @param size Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+int cros_ec_calc_checksum(const uint8_t *data, int size)
+{
+ int csum, i;
+
+ for (i = csum = 0; i < size; i++)
+ csum += data[i];
+ return csum & 0xff;
+}
+
+static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const void *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ int ret;
+
+ switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+ case CROS_EC_IF_SPI:
+ ret = cros_ec_spi_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case CROS_EC_IF_I2C:
+ ret = cros_ec_i2c_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case CROS_EC_IF_LPC:
+ ret = cros_ec_lpc_command(dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len,
+ dinp, din_len);
+ break;
+#endif
+ case CROS_EC_IF_NONE:
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/**
+ * Send a command to the CROS-EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Response data (may be NULL If din_len=0).
+ * If not NULL, it will be updated to point to the data
+ * and will always be double word aligned (64-bits)
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
+ int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
+ int din_len)
+{
+ uint8_t *din;
+ int len;
+
+ if (cmd_version != 0 && !dev->cmd_version_is_supported) {
+ debug("%s: Command version >0 unsupported\n", __func__);
+ return -1;
+ }
+ len = send_command(dev, cmd, cmd_version, dout, dout_len,
+ &din, din_len);
+
+ /* If the command doesn't complete, wait a while */
+ if (len == -EC_RES_IN_PROGRESS) {
+ struct ec_response_get_comms_status *resp;
+ ulong start;
+
+ /* Wait for command to complete */
+ start = get_timer(0);
+ do {
+ int ret;
+
+ mdelay(50); /* Insert some reasonable delay */
+ ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0,
+ NULL, 0,
+ (uint8_t **)&resp, sizeof(*resp));
+ if (ret < 0)
+ return ret;
+
+ if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) {
+ debug("%s: Command %#02x timeout\n",
+ __func__, cmd);
+ return -EC_RES_TIMEOUT;
+ }
+ } while (resp->flags & EC_COMMS_STATUS_PROCESSING);
+
+ /* OK it completed, so read the status response */
+ /* not sure why it was 0 for the last argument */
+ len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0,
+ NULL, 0, &din, din_len);
+ }
+
+ debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp);
+ if (dinp) {
+ /* If we have any data to return, it must be 64bit-aligned */
+ assert(len <= 0 || !((uintptr_t)din & 7));
+ *dinp = din;
+ }
+
+ return len;
+}
+
+/**
+ * Send a command to the CROS-EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param din Response data (may be NULL If din_len=0).
+ * It not NULL, it is a place for ec_command() to copy the
+ * data to.
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const void *dout, int dout_len,
+ void *din, int din_len)
+{
+ uint8_t *in_buffer;
+ int len;
+
+ assert((din_len == 0) || din);
+ len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
+ &in_buffer, din_len);
+ if (len > 0) {
+ /*
+ * If we were asked to put it somewhere, do so, otherwise just
+ * disregard the result.
+ */
+ if (din && in_buffer) {
+ assert(len <= din_len);
+ memmove(din, in_buffer, len);
+ }
+ }
+ return len;
+}
+
+int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan)
+{
+ if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan,
+ sizeof(scan->data)) < sizeof(scan->data))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
+{
+ struct ec_response_get_version *r;
+
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)&r, sizeof(*r)) < sizeof(*r))
+ return -1;
+
+ if (maxlen > sizeof(r->version_string_ro))
+ maxlen = sizeof(r->version_string_ro);
+
+ switch (r->current_image) {
+ case EC_IMAGE_RO:
+ memcpy(id, r->version_string_ro, maxlen);
+ break;
+ case EC_IMAGE_RW:
+ memcpy(id, r->version_string_rw, maxlen);
+ break;
+ default:
+ return -1;
+ }
+
+ id[maxlen - 1] = '\0';
+ return 0;
+}
+
+int cros_ec_read_version(struct cros_ec_dev *dev,
+ struct ec_response_get_version **versionp)
+{
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)versionp, sizeof(**versionp))
+ < sizeof(**versionp))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
+{
+ if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
+ (uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_read_current_image(struct cros_ec_dev *dev,
+ enum ec_current_image *image)
+{
+ struct ec_response_get_version *r;
+
+ if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+ (uint8_t **)&r, sizeof(*r)) < sizeof(*r))
+ return -1;
+
+ *image = r->current_image;
+ return 0;
+}
+
+static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev,
+ struct ec_response_vboot_hash *hash)
+{
+ struct ec_params_vboot_hash p;
+ ulong start;
+
+ start = get_timer(0);
+ while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
+ mdelay(50); /* Insert some reasonable delay */
+
+ p.cmd = EC_VBOOT_HASH_GET;
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) {
+ debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__);
+ return -EC_RES_TIMEOUT;
+ }
+ }
+ return 0;
+}
+
+
+int cros_ec_read_hash(struct cros_ec_dev *dev,
+ struct ec_response_vboot_hash *hash)
+{
+ struct ec_params_vboot_hash p;
+ int rv;
+
+ p.cmd = EC_VBOOT_HASH_GET;
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ /* If the EC is busy calculating the hash, fidget until it's done. */
+ rv = cros_ec_wait_on_hash_done(dev, hash);
+ if (rv)
+ return rv;
+
+ /* If the hash is valid, we're done. Otherwise, we have to kick it off
+ * again and wait for it to complete. Note that we explicitly assume
+ * that hashing zero bytes is always wrong, even though that would
+ * produce a valid hash value. */
+ if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size)
+ return 0;
+
+ debug("%s: No valid hash (status=%d size=%d). Compute one...\n",
+ __func__, hash->status, hash->size);
+
+ p.cmd = EC_VBOOT_HASH_RECALC;
+ p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+ p.nonce_size = 0;
+ p.offset = EC_VBOOT_HASH_OFFSET_RW;
+
+ if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ hash, sizeof(*hash)) < 0)
+ return -1;
+
+ rv = cros_ec_wait_on_hash_done(dev, hash);
+ if (rv)
+ return rv;
+
+ debug("%s: hash done\n", __func__);
+
+ return 0;
+}
+
+static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
+{
+ struct ec_params_vboot_hash p;
+ struct ec_response_vboot_hash *hash;
+
+ /* We don't have an explict command for the EC to discard its current
+ * hash value, so we'll just tell it to calculate one that we know is
+ * wrong (we claim that hashing zero bytes is always invalid).
+ */
+ p.cmd = EC_VBOOT_HASH_RECALC;
+ p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+ p.nonce_size = 0;
+ p.offset = 0;
+ p.size = 0;
+
+ debug("%s:\n", __func__);
+
+ if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+ (uint8_t **)&hash, sizeof(*hash)) < 0)
+ return -1;
+
+ /* No need to wait for it to finish */
+ return 0;
+}
+
+int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
+ uint8_t flags)
+{
+ struct ec_params_reboot_ec p;
+
+ p.cmd = cmd;
+ p.flags = flags;
+
+ if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
+ < 0)
+ return -1;
+
+ if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
+ /*
+ * EC reboot will take place immediately so delay to allow it
+ * to complete. Note that some reboot types (EC_REBOOT_COLD)
+ * will reboot the AP as well, in which case we won't actually
+ * get to this point.
+ */
+ /*
+ * TODO(rspangler@chromium.org): Would be nice if we had a
+ * better way to determine when the reboot is complete. Could
+ * we poll a memory-mapped LPC value?
+ */
+ udelay(50000);
+ }
+
+ return 0;
+}
+
+int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
+{
+ /* no interrupt support : always poll */
+ if (!fdt_gpio_isvalid(&dev->ec_int))
+ return 1;
+
+ return !gpio_get_value(dev->ec_int.gpio);
+}
+
+int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info)
+{
+ if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info,
+ sizeof(*info)) < sizeof(*info))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
+{
+ struct ec_response_host_event_mask *resp;
+
+ /*
+ * Use the B copy of the event flags, because the main copy is already
+ * used by ACPI/SMI.
+ */
+ if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
+ (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
+ return -1;
+
+ if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
+ return -1;
+
+ *events_ptr = resp->mask;
+ return 0;
+}
+
+int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
+{
+ struct ec_params_host_event_mask params;
+
+ params.mask = events;
+
+ /*
+ * Use the B copy of the event flags, so it affects the data returned
+ * by cros_ec_get_host_events().
+ */
+ if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
+ &params, sizeof(params), NULL, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_flash_protect(struct cros_ec_dev *dev,
+ uint32_t set_mask, uint32_t set_flags,
+ struct ec_response_flash_protect *resp)
+{
+ struct ec_params_flash_protect params;
+
+ params.mask = set_mask;
+ params.flags = set_flags;
+
+ if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
+ &params, sizeof(params),
+ resp, sizeof(*resp)) < sizeof(*resp))
+ return -1;
+
+ return 0;
+}
+
+static int cros_ec_check_version(struct cros_ec_dev *dev)
+{
+ struct ec_params_hello req;
+ struct ec_response_hello *resp;
+
+#ifdef CONFIG_CROS_EC_LPC
+ /* LPC has its own way of doing this */
+ if (dev->interface == CROS_EC_IF_LPC)
+ return cros_ec_lpc_check_version(dev);
+#endif
+
+ /*
+ * TODO(sjg@chromium.org).
+ * There is a strange oddity here with the EC. We could just ignore
+ * the response, i.e. pass the last two parameters as NULL and 0.
+ * In this case we won't read back very many bytes from the EC.
+ * On the I2C bus the EC gets upset about this and will try to send
+ * the bytes anyway. This means that we will have to wait for that
+ * to complete before continuing with a new EC command.
+ *
+ * This problem is probably unique to the I2C bus.
+ *
+ * So for now, just read all the data anyway.
+ */
+ dev->cmd_version_is_supported = 1;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+ (uint8_t **)&resp, sizeof(*resp)) > 0) {
+ /* It appears to understand new version commands */
+ dev->cmd_version_is_supported = 1;
+ } else {
+ dev->cmd_version_is_supported = 0;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req,
+ sizeof(req), (uint8_t **)&resp,
+ sizeof(*resp)) < 0) {
+ debug("%s: Failed both old and new command style\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int cros_ec_test(struct cros_ec_dev *dev)
+{
+ struct ec_params_hello req;
+ struct ec_response_hello *resp;
+
+ req.in_data = 0x12345678;
+ if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+ (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
+ printf("ec_command_inptr() returned error\n");
+ return -1;
+ }
+ if (resp->out_data != req.in_data + 0x01020304) {
+ printf("Received invalid handshake %x\n", resp->out_data);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
+ uint32_t *offset, uint32_t *size)
+{
+ struct ec_params_flash_region_info p;
+ struct ec_response_flash_region_info *r;
+ int ret;
+
+ p.region = region;
+ ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
+ EC_VER_FLASH_REGION_INFO,
+ &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
+ if (ret != sizeof(*r))
+ return -1;
+
+ if (offset)
+ *offset = r->offset;
+ if (size)
+ *size = r->size;
+
+ return 0;
+}
+
+int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_erase p;
+
+ p.offset = offset;
+ p.size = size;
+ return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
+ NULL, 0);
+}
+
+/**
+ * Write a single block to the flash
+ *
+ * Write a block of data to the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to write for a particular region.
+ *
+ * Attempting to write to the region where the EC is currently running from
+ * will result in an error.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to write
+ * @param offset Offset within flash to write to.
+ * @param size Number of bytes to write
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
+ const uint8_t *data, uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_write p;
+
+ p.offset = offset;
+ p.size = size;
+ assert(data && p.size <= sizeof(p.data));
+ memcpy(p.data, data, p.size);
+
+ return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
+ &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
+}
+
+/**
+ * Return optimal flash write burst size
+ */
+static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev)
+{
+ struct ec_params_flash_write p;
+ return sizeof(p.data);
+}
+
+/**
+ * Check if a block of data is erased (all 0xff)
+ *
+ * This function is useful when dealing with flash, for checking whether a
+ * data block is erased and thus does not need to be programmed.
+ *
+ * @param data Pointer to data to check (must be word-aligned)
+ * @param size Number of bytes to check (must be word-aligned)
+ * @return 0 if erased, non-zero if any word is not erased
+ */
+static int cros_ec_data_is_erased(const uint32_t *data, int size)
+{
+ assert(!(size & 3));
+ size /= sizeof(uint32_t);
+ for (; size > 0; size -= 4, data++)
+ if (*data != -1U)
+ return 0;
+
+ return 1;
+}
+
+int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
+ uint32_t offset, uint32_t size)
+{
+ uint32_t burst = cros_ec_flash_write_burst_size(dev);
+ uint32_t end, off;
+ int ret;
+
+ /*
+ * TODO: round up to the nearest multiple of write size. Can get away
+ * without that on link right now because its write size is 4 bytes.
+ */
+ end = offset + size;
+ for (off = offset; off < end; off += burst, data += burst) {
+ uint32_t todo;
+
+ /* If the data is empty, there is no point in programming it */
+ todo = min(end - off, burst);
+ if (dev->optimise_flash_write &&
+ cros_ec_data_is_erased((uint32_t *)data, todo))
+ continue;
+
+ ret = cros_ec_flash_write_block(dev, data, off, todo);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Read a single block from the flash
+ *
+ * Read a block of data from the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to read for a particular region.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to read into
+ * @param offset Offset within flash to read from
+ * @param size Number of bytes to read
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data,
+ uint32_t offset, uint32_t size)
+{
+ struct ec_params_flash_read p;
+
+ p.offset = offset;
+ p.size = size;
+
+ return ec_command(dev, EC_CMD_FLASH_READ, 0,
+ &p, sizeof(p), data, size) >= 0 ? 0 : -1;
+}
+
+int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
+ uint32_t size)
+{
+ uint32_t burst = cros_ec_flash_write_burst_size(dev);
+ uint32_t end, off;
+ int ret;
+
+ end = offset + size;
+ for (off = offset; off < end; off += burst, data += burst) {
+ ret = cros_ec_flash_read_block(dev, data, off,
+ min(end - off, burst));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
+ const uint8_t *image, int image_size)
+{
+ uint32_t rw_offset, rw_size;
+ int ret;
+
+ if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size))
+ return -1;
+ if (image_size > rw_size)
+ return -1;
+
+ /* Invalidate the existing hash, just in case the AP reboots
+ * unexpectedly during the update. If that happened, the EC RW firmware
+ * would be invalid, but the EC would still have the original hash.
+ */
+ ret = cros_ec_invalidate_hash(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Erase the entire RW section, so that the EC doesn't see any garbage
+ * past the new image if it's smaller than the current image.
+ *
+ * TODO: could optimize this to erase just the current image, since
+ * presumably everything past that is 0xff's. But would still need to
+ * round up to the nearest multiple of erase size.
+ */
+ ret = cros_ec_flash_erase(dev, rw_offset, rw_size);
+ if (ret)
+ return ret;
+
+ /* Write the image */
+ ret = cros_ec_flash_write(dev, image, rw_offset, image_size);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block)
+{
+ struct ec_params_vbnvcontext p;
+ int len;
+
+ p.op = EC_VBNV_CONTEXT_OP_READ;
+
+ len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+ &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE);
+ if (len < EC_VBNV_BLOCK_SIZE)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
+{
+ struct ec_params_vbnvcontext p;
+ int len;
+
+ p.op = EC_VBNV_CONTEXT_OP_WRITE;
+ memcpy(p.block, block, sizeof(p.block));
+
+ len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+ &p, sizeof(p), NULL, 0);
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
+{
+ struct ec_params_ldo_set params;
+
+ params.index = index;
+ params.state = state;
+
+ if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
+ &params, sizeof(params),
+ NULL, 0))
+ return -1;
+
+ return 0;
+}
+
+int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
+{
+ struct ec_params_ldo_get params;
+ struct ec_response_ldo_get *resp;
+
+ params.index = index;
+
+ if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
+ &params, sizeof(params),
+ (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
+ return -1;
+
+ *state = resp->state;
+
+ return 0;
+}
+
+/**
+ * Decode MBKP details from the device tree and allocate a suitable device.
+ *
+ * @param blob Device tree blob
+ * @param node Node to decode from
+ * @param devp Returns a pointer to the new allocated device
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_decode_fdt(const void *blob, int node,
+ struct cros_ec_dev **devp)
+{
+ enum fdt_compat_id compat;
+ struct cros_ec_dev *dev;
+ int parent;
+
+ /* See what type of parent we are inside (this is expensive) */
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Cannot find node parent\n", __func__);
+ return -1;
+ }
+
+ dev = &static_dev;
+ dev->node = node;
+ dev->parent_node = parent;
+
+ compat = fdtdec_lookup(blob, parent);
+ switch (compat) {
+#ifdef CONFIG_CROS_EC_SPI
+ case COMPAT_SAMSUNG_EXYNOS_SPI:
+ dev->interface = CROS_EC_IF_SPI;
+ if (cros_ec_spi_decode_fdt(dev, blob))
+ return -1;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case COMPAT_SAMSUNG_S3C2440_I2C:
+ dev->interface = CROS_EC_IF_I2C;
+ if (cros_ec_i2c_decode_fdt(dev, blob))
+ return -1;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case COMPAT_INTEL_LPC:
+ dev->interface = CROS_EC_IF_LPC;
+ break;
+#endif
+ default:
+ debug("%s: Unknown compat id %d\n", __func__, compat);
+ return -1;
+ }
+
+ fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
+ dev->optimise_flash_write = fdtdec_get_bool(blob, node,
+ "optimise-flash-write");
+ *devp = dev;
+
+ return 0;
+}
+
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
+ char id[MSG_BYTES];
+ struct cros_ec_dev *dev;
+ int node = 0;
+
+ *cros_ecp = NULL;
+ do {
+ node = fdtdec_next_compatible(blob, node,
+ COMPAT_GOOGLE_CROS_EC);
+ if (node < 0) {
+ debug("%s: Node not found\n", __func__);
+ return 0;
+ }
+ } while (!fdtdec_get_is_enabled(blob, node));
+
+ if (cros_ec_decode_fdt(blob, node, &dev)) {
+ debug("%s: Failed to decode device.\n", __func__);
+ return -CROS_EC_ERR_FDT_DECODE;
+ }
+
+ switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+ case CROS_EC_IF_SPI:
+ if (cros_ec_spi_init(dev, blob)) {
+ debug("%s: Could not setup SPI interface\n", __func__);
+ return -CROS_EC_ERR_DEV_INIT;
+ }
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+ case CROS_EC_IF_I2C:
+ if (cros_ec_i2c_init(dev, blob))
+ return -CROS_EC_ERR_DEV_INIT;
+ break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+ case CROS_EC_IF_LPC:
+ if (cros_ec_lpc_init(dev, blob))
+ return -CROS_EC_ERR_DEV_INIT;
+ break;
+#endif
+ case CROS_EC_IF_NONE:
+ default:
+ return 0;
+ }
+
+ /* we will poll the EC interrupt line */
+ fdtdec_setup_gpio(&dev->ec_int);
+ if (fdt_gpio_isvalid(&dev->ec_int))
+ gpio_direction_input(dev->ec_int.gpio);
+
+ if (cros_ec_check_version(dev)) {
+ debug("%s: Could not detect CROS-EC version\n", __func__);
+ return -CROS_EC_ERR_CHECK_VERSION;
+ }
+
+ if (cros_ec_read_id(dev, id, sizeof(id))) {
+ debug("%s: Could not read KBC ID\n", __func__);
+ return -CROS_EC_ERR_READ_ID;
+ }
+
+ /* Remember this device for use by the cros_ec command */
+ last_dev = *cros_ecp = dev;
+ debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+ return 0;
+}
+
+#ifdef CONFIG_CMD_CROS_EC
+int cros_ec_decode_region(int argc, char * const argv[])
+{
+ if (argc > 0) {
+ if (0 == strcmp(*argv, "rw"))
+ return EC_FLASH_REGION_RW;
+ else if (0 == strcmp(*argv, "ro"))
+ return EC_FLASH_REGION_RO;
+
+ debug("%s: Invalid region '%s'\n", __func__, *argv);
+ } else {
+ debug("%s: Missing region parameter\n", __func__);
+ }
+
+ return -1;
+}
+
+/**
+ * Perform a flash read or write command
+ *
+ * @param dev CROS-EC device to read/write
+ * @param is_write 1 do to a write, 0 to do a read
+ * @param argc Number of arguments
+ * @param argv Arguments (2 is region, 3 is address)
+ * @return 0 for ok, 1 for a usage error or -ve for ec command error
+ * (negative EC_RES_...)
+ */
+static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
+ char * const argv[])
+{
+ uint32_t offset, size = -1U, region_size;
+ unsigned long addr;
+ char *endp;
+ int region;
+ int ret;
+
+ region = cros_ec_decode_region(argc - 2, argv + 2);
+ if (region == -1)
+ return 1;
+ if (argc < 4)
+ return 1;
+ addr = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ return 1;
+ if (argc > 4) {
+ size = simple_strtoul(argv[4], &endp, 16);
+ if (*argv[4] == 0 || *endp != 0)
+ return 1;
+ }
+
+ ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
+ if (ret) {
+ debug("%s: Could not read region info\n", __func__);
+ return ret;
+ }
+ if (size == -1U)
+ size = region_size;
+
+ ret = is_write ?
+ cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
+ cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
+ if (ret) {
+ debug("%s: Could not %s region\n", __func__,
+ is_write ? "write" : "read");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct cros_ec_dev *dev = last_dev;
+ const char *cmd;
+ int ret = 0;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ cmd = argv[1];
+ if (0 == strcmp("init", cmd)) {
+ ret = cros_ec_init(gd->fdt_blob, &dev);
+ if (ret) {
+ printf("Could not init cros_ec device (err %d)\n", ret);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Just use the last allocated device; there should be only one */
+ if (!last_dev) {
+ printf("No CROS-EC device available\n");
+ return 1;
+ }
+ if (0 == strcmp("id", cmd)) {
+ char id[MSG_BYTES];
+
+ if (cros_ec_read_id(dev, id, sizeof(id))) {
+ debug("%s: Could not read KBC ID\n", __func__);
+ return 1;
+ }
+ printf("%s\n", id);
+ } else if (0 == strcmp("info", cmd)) {
+ struct ec_response_cros_ec_info info;
+
+ if (cros_ec_info(dev, &info)) {
+ debug("%s: Could not read KBC info\n", __func__);
+ return 1;
+ }
+ printf("rows = %u\n", info.rows);
+ printf("cols = %u\n", info.cols);
+ printf("switches = %#x\n", info.switches);
+ } else if (0 == strcmp("curimage", cmd)) {
+ enum ec_current_image image;
+
+ if (cros_ec_read_current_image(dev, &image)) {
+ debug("%s: Could not read KBC image\n", __func__);
+ return 1;
+ }
+ printf("%d\n", image);
+ } else if (0 == strcmp("hash", cmd)) {
+ struct ec_response_vboot_hash hash;
+ int i;
+
+ if (cros_ec_read_hash(dev, &hash)) {
+ debug("%s: Could not read KBC hash\n", __func__);
+ return 1;
+ }
+
+ if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
+ printf("type: SHA-256\n");
+ else
+ printf("type: %d\n", hash.hash_type);
+
+ printf("offset: 0x%08x\n", hash.offset);
+ printf("size: 0x%08x\n", hash.size);
+
+ printf("digest: ");
+ for (i = 0; i < hash.digest_size; i++)
+ printf("%02x", hash.hash_digest[i]);
+ printf("\n");
+ } else if (0 == strcmp("reboot", cmd)) {
+ int region;
+ enum ec_reboot_cmd cmd;
+
+ if (argc >= 3 && !strcmp(argv[2], "cold"))
+ cmd = EC_REBOOT_COLD;
+ else {
+ region = cros_ec_decode_region(argc - 2, argv + 2);
+ if (region == EC_FLASH_REGION_RO)
+ cmd = EC_REBOOT_JUMP_RO;
+ else if (region == EC_FLASH_REGION_RW)
+ cmd = EC_REBOOT_JUMP_RW;
+ else
+ return CMD_RET_USAGE;
+ }
+
+ if (cros_ec_reboot(dev, cmd, 0)) {
+ debug("%s: Could not reboot KBC\n", __func__);
+ return 1;
+ }
+ } else if (0 == strcmp("events", cmd)) {
+ uint32_t events;
+
+ if (cros_ec_get_host_events(dev, &events)) {
+ debug("%s: Could not read host events\n", __func__);
+ return 1;
+ }
+ printf("0x%08x\n", events);
+ } else if (0 == strcmp("clrevents", cmd)) {
+ uint32_t events = 0x7fffffff;
+
+ if (argc >= 3)
+ events = simple_strtol(argv[2], NULL, 0);
+
+ if (cros_ec_clear_host_events(dev, events)) {
+ debug("%s: Could not clear host events\n", __func__);
+ return 1;
+ }
+ } else if (0 == strcmp("read", cmd)) {
+ ret = do_read_write(dev, 0, argc, argv);
+ if (ret > 0)
+ return CMD_RET_USAGE;
+ } else if (0 == strcmp("write", cmd)) {
+ ret = do_read_write(dev, 1, argc, argv);
+ if (ret > 0)
+ return CMD_RET_USAGE;
+ } else if (0 == strcmp("erase", cmd)) {
+ int region = cros_ec_decode_region(argc - 2, argv + 2);
+ uint32_t offset, size;
+
+ if (region == -1)
+ return CMD_RET_USAGE;
+ if (cros_ec_flash_offset(dev, region, &offset, &size)) {
+ debug("%s: Could not read region info\n", __func__);
+ ret = -1;
+ } else {
+ ret = cros_ec_flash_erase(dev, offset, size);
+ if (ret) {
+ debug("%s: Could not erase region\n",
+ __func__);
+ }
+ }
+ } else if (0 == strcmp("regioninfo", cmd)) {
+ int region = cros_ec_decode_region(argc - 2, argv + 2);
+ uint32_t offset, size;
+
+ if (region == -1)
+ return CMD_RET_USAGE;
+ ret = cros_ec_flash_offset(dev, region, &offset, &size);
+ if (ret) {
+ debug("%s: Could not read region info\n", __func__);
+ } else {
+ printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
+ "RO" : "RW");
+ printf("Offset: %x\n", offset);
+ printf("Size: %x\n", size);
+ }
+ } else if (0 == strcmp("vbnvcontext", cmd)) {
+ uint8_t block[EC_VBNV_BLOCK_SIZE];
+ char buf[3];
+ int i, len;
+ unsigned long result;
+
+ if (argc <= 2) {
+ ret = cros_ec_read_vbnvcontext(dev, block);
+ if (!ret) {
+ printf("vbnv_block: ");
+ for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
+ printf("%02x", block[i]);
+ putc('\n');
+ }
+ } else {
+ /*
+ * TODO(clchiou): Move this to a utility function as
+ * cmd_spi might want to call it.
+ */
+ memset(block, 0, EC_VBNV_BLOCK_SIZE);
+ len = strlen(argv[2]);
+ buf[2] = '\0';
+ for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
+ if (i * 2 >= len)
+ break;
+ buf[0] = argv[2][i * 2];
+ if (i * 2 + 1 >= len)
+ buf[1] = '0';
+ else
+ buf[1] = argv[2][i * 2 + 1];
+ strict_strtoul(buf, 16, &result);
+ block[i] = result;
+ }
+ ret = cros_ec_write_vbnvcontext(dev, block);
+ }
+ if (ret) {
+ debug("%s: Could not %s VbNvContext\n", __func__,
+ argc <= 2 ? "read" : "write");
+ }
+ } else if (0 == strcmp("test", cmd)) {
+ int result = cros_ec_test(dev);
+
+ if (result)
+ printf("Test failed with error %d\n", result);
+ else
+ puts("Test passed\n");
+ } else if (0 == strcmp("version", cmd)) {
+ struct ec_response_get_version *p;
+ char *build_string;
+
+ ret = cros_ec_read_version(dev, &p);
+ if (!ret) {
+ /* Print versions */
+ printf("RO version: %1.*s\n",
+ sizeof(p->version_string_ro),
+ p->version_string_ro);
+ printf("RW version: %1.*s\n",
+ sizeof(p->version_string_rw),
+ p->version_string_rw);
+ printf("Firmware copy: %s\n",
+ (p->current_image <
+ ARRAY_SIZE(ec_current_image_name) ?
+ ec_current_image_name[p->current_image] :
+ "?"));
+ ret = cros_ec_read_build_info(dev, &build_string);
+ if (!ret)
+ printf("Build info: %s\n", build_string);
+ }
+ } else if (0 == strcmp("ldo", cmd)) {
+ uint8_t index, state;
+ char *endp;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+ index = simple_strtoul(argv[2], &endp, 10);
+ if (*argv[2] == 0 || *endp != 0)
+ return CMD_RET_USAGE;
+ if (argc > 3) {
+ state = simple_strtoul(argv[3], &endp, 10);
+ if (*argv[3] == 0 || *endp != 0)
+ return CMD_RET_USAGE;
+ ret = cros_ec_set_ldo(dev, index, state);
+ } else {
+ ret = cros_ec_get_ldo(dev, index, &state);
+ if (!ret) {
+ printf("LDO%d: %s\n", index,
+ state == EC_LDO_STATE_ON ?
+ "on" : "off");
+ }
+ }
+
+ if (ret) {
+ debug("%s: Could not access LDO%d\n", __func__, index);
+ return ret;
+ }
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ if (ret < 0) {
+ printf("Error: CROS-EC command failed (error %d)\n", ret);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ crosec, 5, 1, do_cros_ec,
+ "CROS-EC utility command",
+ "init Re-init CROS-EC (done on startup automatically)\n"
+ "crosec id Read CROS-EC ID\n"
+ "crosec info Read CROS-EC info\n"
+ "crosec curimage Read CROS-EC current image\n"
+ "crosec hash Read CROS-EC hash\n"
+ "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
+ "crosec events Read CROS-EC host events\n"
+ "crosec clrevents [mask] Clear CROS-EC host events\n"
+ "crosec regioninfo <ro|rw> Read image info\n"
+ "crosec erase <ro|rw> Erase EC image\n"
+ "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
+ "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
+ "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
+ "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
+ "crosec test run tests on cros_ec\n"
+ "crosec version Read CROS-EC version"
+);
+#endif
diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c
new file mode 100644
index 0000000..b0060ac
--- /dev/null
+++ b/drivers/misc/cros_ec_i2c.c
@@ -0,0 +1,199 @@
+/*
+ * Chromium OS cros_ec driver - I2C interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <cros_ec.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ int old_bus = 0;
+ /* version8, cmd8, arglen8, out8[dout_len], csum8 */
+ int out_bytes = dout_len + 4;
+ /* response8, arglen8, in8[din_len], checksum8 */
+ int in_bytes = din_len + 3;
+ uint8_t *ptr;
+ /* Receive input data, so that args will be dword aligned */
+ uint8_t *in_ptr;
+ int ret;
+
+ old_bus = i2c_get_bus_num();
+
+ /*
+ * Sanity-check I/O sizes given transaction overhead in internal
+ * buffers.
+ */
+ if (out_bytes > sizeof(dev->dout)) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+ if (in_bytes > sizeof(dev->din)) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -1;
+ }
+ assert(dout_len >= 0);
+ assert(dinp);
+
+ /*
+ * Copy command and data into output buffer so we can do a single I2C
+ * burst transaction.
+ */
+ ptr = dev->dout;
+
+ /*
+ * in_ptr starts of pointing to a dword-aligned input data buffer.
+ * We decrement it back by the number of header bytes we expect to
+ * receive, so that the first parameter of the resulting input data
+ * will be dword aligned.
+ */
+ in_ptr = dev->din + sizeof(int64_t);
+ if (!dev->cmd_version_is_supported) {
+ /* Send an old-style command */
+ *ptr++ = cmd;
+ out_bytes = dout_len + 1;
+ in_bytes = din_len + 2;
+ in_ptr--; /* Expect just a status byte */
+ } else {
+ *ptr++ = EC_CMD_VERSION0 + cmd_version;
+ *ptr++ = cmd;
+ *ptr++ = dout_len;
+ in_ptr -= 2; /* Expect status, length bytes */
+ }
+ memcpy(ptr, dout, dout_len);
+ ptr += dout_len;
+
+ if (dev->cmd_version_is_supported)
+ *ptr++ = (uint8_t)
+ cros_ec_calc_checksum(dev->dout, dout_len + 3);
+
+ /* Set to the proper i2c bus */
+ if (i2c_set_bus_num(dev->bus_num)) {
+ debug("%s: Cannot change to I2C bus %d\n", __func__,
+ dev->bus_num);
+ return -1;
+ }
+
+ /* Send output data */
+ cros_ec_dump_data("out", -1, dev->dout, out_bytes);
+ ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
+ if (ret) {
+ debug("%s: Cannot complete I2C write to 0x%x\n",
+ __func__, dev->addr);
+ ret = -1;
+ }
+
+ if (!ret) {
+ ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
+ if (ret) {
+ debug("%s: Cannot complete I2C read from 0x%x\n",
+ __func__, dev->addr);
+ ret = -1;
+ }
+ }
+
+ /* Return to original bus number */
+ i2c_set_bus_num(old_bus);
+ if (ret)
+ return ret;
+
+ if (*in_ptr != EC_RES_SUCCESS) {
+ debug("%s: Received bad result code %d\n", __func__, *in_ptr);
+ return -(int)*in_ptr;
+ }
+
+ if (dev->cmd_version_is_supported) {
+ int len, csum;
+
+ len = in_ptr[1];
+ if (len + 3 > sizeof(dev->din)) {
+ debug("%s: Received length %#02x too large\n",
+ __func__, len);
+ return -1;
+ }
+ csum = cros_ec_calc_checksum(in_ptr, 2 + len);
+ if (csum != in_ptr[2 + len]) {
+ debug("%s: Invalid checksum rx %#02x, calced %#02x\n",
+ __func__, in_ptr[2 + din_len], csum);
+ return -1;
+ }
+ din_len = min(din_len, len);
+ cros_ec_dump_data("in", -1, in_ptr, din_len + 3);
+ } else {
+ cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes);
+ }
+
+ /* Return pointer to dword-aligned input data, if any */
+ *dinp = dev->din + sizeof(int64_t);
+
+ return din_len;
+}
+
+int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+ /* Decode interface-specific FDT params */
+ dev->max_frequency = fdtdec_get_int(blob, dev->node,
+ "i2c-max-frequency", 100000);
+ dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
+ if (dev->bus_num == -1) {
+ debug("%s: Failed to read bus number\n", __func__);
+ return -1;
+ }
+ dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
+ if (dev->addr == -1) {
+ debug("%s: Failed to read device address\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Initialize I2C protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
+{
+ i2c_init(dev->max_frequency, dev->addr);
+
+ dev->cmd_version_is_supported = 0;
+
+ return 0;
+}
diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c
new file mode 100644
index 0000000..cf0435b
--- /dev/null
+++ b/drivers/misc/cros_ec_lpc.c
@@ -0,0 +1,283 @@
+/*
+ * Chromium OS cros_ec driver - LPC interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cros_ec.h>
+#include <asm/io.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...) debug(fmt, ##b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+static int wait_for_sync(struct cros_ec_dev *dev)
+{
+ unsigned long start;
+
+ start = get_timer(0);
+ while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) {
+ if (get_timer(start) > 1000) {
+ debug("%s: Timeout waiting for CROS_EC sync\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Send a command to a LPC CROS_EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS_EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Place to put pointer to response data
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int old_lpc_command(struct cros_ec_dev *dev, uint8_t cmd,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ int ret, i;
+
+ if (dout_len > EC_OLD_PARAM_SIZE) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+
+ if (din_len > EC_OLD_PARAM_SIZE) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -1;
+ }
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting ready\n", __func__);
+ return -1;
+ }
+
+ debug_trace("cmd: %02x, ", cmd);
+ for (i = 0; i < dout_len; i++) {
+ debug_trace("%02x ", dout[i]);
+ outb(dout[i], EC_LPC_ADDR_OLD_PARAM + i);
+ }
+ outb(cmd, EC_LPC_ADDR_HOST_CMD);
+ debug_trace("\n");
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting ready\n", __func__);
+ return -1;
+ }
+
+ ret = inb(EC_LPC_ADDR_HOST_DATA);
+ if (ret) {
+ debug("%s: CROS_EC result code %d\n", __func__, ret);
+ return -ret;
+ }
+
+ debug_trace("resp: %02x, ", ret);
+ for (i = 0; i < din_len; i++) {
+ dev->din[i] = inb(EC_LPC_ADDR_OLD_PARAM + i);
+ debug_trace("%02x ", dev->din[i]);
+ }
+ debug_trace("\n");
+ *dinp = dev->din;
+
+ return din_len;
+}
+
+int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ const int cmd_addr = EC_LPC_ADDR_HOST_CMD;
+ const int data_addr = EC_LPC_ADDR_HOST_DATA;
+ const int args_addr = EC_LPC_ADDR_HOST_ARGS;
+ const int param_addr = EC_LPC_ADDR_HOST_PARAM;
+
+ struct ec_lpc_host_args args;
+ uint8_t *d;
+ int csum;
+ int i;
+
+ /* Fall back to old-style command interface if args aren't supported */
+ if (!dev->cmd_version_is_supported)
+ return old_lpc_command(dev, cmd, dout, dout_len, dinp,
+ din_len);
+
+ if (dout_len > EC_HOST_PARAM_SIZE) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+
+ /* Fill in args */
+ args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
+ args.command_version = cmd_version;
+ args.data_size = dout_len;
+
+ /* Calculate checksum */
+ csum = cmd + args.flags + args.command_version + args.data_size;
+ for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++)
+ csum += *d;
+
+ args.checksum = (uint8_t)csum;
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting ready\n", __func__);
+ return -1;
+ }
+
+ /* Write args */
+ for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+ outb(*d, args_addr + i);
+
+ /* Write data, if any */
+ debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version);
+ for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) {
+ outb(*d, param_addr + i);
+ debug_trace("%02x ", *d);
+ }
+
+ outb(cmd, cmd_addr);
+ debug_trace("\n");
+
+ if (wait_for_sync(dev)) {
+ debug("%s: Timeout waiting for response\n", __func__);
+ return -1;
+ }
+
+ /* Check result */
+ i = inb(data_addr);
+ if (i) {
+ debug("%s: CROS_EC result code %d\n", __func__, i);
+ return -i;
+ }
+
+ /* Read back args */
+ for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+ *d = inb(args_addr + i);
+
+ /*
+ * If EC didn't modify args flags, then somehow we sent a new-style
+ * command to an old EC, which means it would have read its params
+ * from the wrong place.
+ */
+ if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) {
+ debug("%s: CROS_EC protocol mismatch\n", __func__);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (args.data_size > din_len) {
+ debug("%s: CROS_EC returned too much data %d > %d\n",
+ __func__, args.data_size, din_len);
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ /* Read data, if any */
+ for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) {
+ *d = inb(param_addr + i);
+ debug_trace("%02x ", *d);
+ }
+ debug_trace("\n");
+
+ /* Verify checksum */
+ csum = cmd + args.flags + args.command_version + args.data_size;
+ for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++)
+ csum += *d;
+
+ if (args.checksum != (uint8_t)csum) {
+ debug("%s: CROS_EC response has invalid checksum\n", __func__);
+ return -EC_RES_INVALID_CHECKSUM;
+ }
+ *dinp = dev->din;
+
+ /* Return actual amount of data received */
+ return args.data_size;
+}
+
+/**
+ * Initialize LPC protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
+{
+ int byte, i;
+
+ /* See if we can find an EC at the other end */
+ byte = 0xff;
+ byte &= inb(EC_LPC_ADDR_HOST_CMD);
+ byte &= inb(EC_LPC_ADDR_HOST_DATA);
+ for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++)
+ byte &= inb(EC_LPC_ADDR_HOST_PARAM + i);
+ if (byte == 0xff) {
+ debug("%s: CROS_EC device not found on LPC bus\n",
+ __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Test if LPC command args are supported.
+ *
+ * The cheapest way to do this is by looking for the memory-mapped
+ * flag. This is faster than sending a new-style 'hello' command and
+ * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
+ * in args when it responds.
+ */
+int cros_ec_lpc_check_version(struct cros_ec_dev *dev)
+{
+ if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' &&
+ inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1)
+ == 'C' &&
+ (inb(EC_LPC_ADDR_MEMMAP +
+ EC_MEMMAP_HOST_CMD_FLAGS) &
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) {
+ dev->cmd_version_is_supported = 1;
+ } else {
+ /* We are going to use the old IO ports */
+ dev->cmd_version_is_supported = 0;
+ }
+ debug("lpc: version %s\n", dev->cmd_version_is_supported ?
+ "new" : "old");
+
+ return 0;
+}
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
new file mode 100644
index 0000000..e15c833
--- /dev/null
+++ b/drivers/misc/cros_ec_spi.c
@@ -0,0 +1,161 @@
+/*
+ * Chromium OS cros_ec driver - SPI interface
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * The Matrix Keyboard Protocol driver handles talking to the keyboard
+ * controller chip. Mostly this is for keyboard functions, but some other
+ * things have slipped in, so we provide generic services to talk to the
+ * KBC.
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <spi.h>
+
+/**
+ * Send a command to a LPC CROS_EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS_EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Returns pointer to response data. This will be
+ * untouched unless we return a value > 0.
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len)
+{
+ int in_bytes = din_len + 4; /* status, length, checksum, trailer */
+ uint8_t *out;
+ uint8_t *p;
+ int csum, len;
+ int rv;
+
+ /*
+ * Sanity-check input size to make sure it plus transaction overhead
+ * fits in the internal device buffer.
+ */
+ if (in_bytes > sizeof(dev->din)) {
+ debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+ return -1;
+ }
+
+ /* We represent message length as a byte */
+ if (dout_len > 0xff) {
+ debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+ return -1;
+ }
+
+ /*
+ * Clear input buffer so we don't get false hits for MSG_HEADER
+ */
+ memset(dev->din, '\0', in_bytes);
+
+ if (spi_claim_bus(dev->spi)) {
+ debug("%s: Cannot claim SPI bus\n", __func__);
+ return -1;
+ }
+
+ out = dev->dout;
+ out[0] = cmd_version;
+ out[1] = cmd;
+ out[2] = (uint8_t)dout_len;
+ memcpy(out + 3, dout, dout_len);
+ csum = cros_ec_calc_checksum(out, 3)
+ + cros_ec_calc_checksum(dout, dout_len);
+ out[3 + dout_len] = (uint8_t)csum;
+
+ /*
+ * Send output data and receive input data starting such that the
+ * message body will be dword aligned.
+ */
+ p = dev->din + sizeof(int64_t) - 2;
+ len = dout_len + 4;
+ cros_ec_dump_data("out", cmd, out, len);
+ rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ spi_release_bus(dev->spi);
+
+ if (rv) {
+ debug("%s: Cannot complete SPI transfer\n", __func__);
+ return -1;
+ }
+
+ len = min(p[1], din_len);
+ cros_ec_dump_data("in", -1, p, len + 3);
+
+ /* Response code is first byte of message */
+ if (p[0] != EC_RES_SUCCESS) {
+ printf("%s: Returned status %d\n", __func__, p[0]);
+ return -(int)(p[0]);
+ }
+
+ /* Check checksum */
+ csum = cros_ec_calc_checksum(p, len + 2);
+ if (csum != p[len + 2]) {
+ debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__,
+ p[2 + len], csum);
+ return -1;
+ }
+
+ /* Anything else is the response data */
+ *dinp = p + 2;
+
+ return len;
+}
+
+int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+ /* Decode interface-specific FDT params */
+ dev->max_frequency = fdtdec_get_int(blob, dev->node,
+ "spi-max-frequency", 500000);
+ dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0);
+
+ return 0;
+}
+
+/**
+ * Initialize SPI protocol.
+ *
+ * @param dev CROS_EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
+{
+ dev->spi = spi_setup_slave_fdt(blob, dev->parent_node,
+ dev->cs, dev->max_frequency, 0);
+ if (!dev->spi) {
+ debug("%s: Could not setup SPI slave\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 83d2df7..73f7195 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -254,7 +254,7 @@ err_out:
}
static unsigned long
-mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
+mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
{
int err = 0;
struct mmc *mmc = find_mmc_device(dev_num);
@@ -266,7 +266,8 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
printf("\n\nCaution! Your devices Erase group is 0x%x\n"
- "The erase range would be change to 0x%lx~0x%lx\n\n",
+ "The erase range would be change to "
+ "0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
((start + blkcnt + mmc->erase_grp_size)
& ~(mmc->erase_grp_size - 1)) - 1);
@@ -289,14 +290,14 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
}
static ulong
-mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
+mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
{
struct mmc_cmd cmd;
struct mmc_data data;
int timeout = 1000;
if ((start + blkcnt) > mmc->block_dev.lba) {
- printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
+ printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
@@ -346,7 +347,7 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
}
static ulong
-mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
+mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
{
lbaint_t cur, blocks_todo = blkcnt;
@@ -369,7 +370,7 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
return blkcnt;
}
-static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start,
+static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
lbaint_t blkcnt)
{
struct mmc_cmd cmd;
@@ -408,7 +409,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start,
return blkcnt;
}
-static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
+static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
{
lbaint_t cur, blocks_todo = blkcnt;
@@ -420,7 +421,7 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
return 0;
if ((start + blkcnt) > mmc->block_dev.lba) {
- printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
+ printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 25f8752..25a5710 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1797,7 +1797,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
};
int i;
- for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
info->vendor = modes[i];
info->start[0] =
(ulong)map_physmem(base,
@@ -1883,8 +1883,7 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
/* Issue FLASH reset command */
flash_cmd_reset(info);
- for (cfi_offset=0;
- cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
+ for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi);
cfi_offset++) {
flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
FLASH_CMD_CFI);
@@ -2336,7 +2335,7 @@ void flash_protect_default(void)
#endif
#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
- for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
+ for (i = 0; i < ARRAY_SIZE(apl); i++) {
debug("autoprotecting from %08lx to %08lx\n",
apl[i].start, apl[i].start + apl[i].size - 1);
flash_protect(FLAG_PROTECT_SET,
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index daa8003..a19cec5 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -37,7 +37,6 @@ static struct serial_device *serial_current;
* Table with supported baudrates (defined in config_xyz.h)
*/
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
/**
* serial_null() - Void registration routine of a serial driver
@@ -74,11 +73,11 @@ static int on_baudrate(const char *name, const char *value, enum env_op op,
if (gd->baudrate == baudrate)
return 0;
- for (i = 0; i < N_BAUDRATES; ++i) {
+ for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
if (baudrate == baudrate_table[i])
break;
}
- if (i == N_BAUDRATES) {
+ if (i == ARRAY_SIZE(baudrate_table)) {
if ((flags & H_FORCE) == 0)
printf("## Baudrate %d bps not supported\n",
baudrate);
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 01378d0..7a25a35 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -465,6 +465,28 @@ static int process_nodes(const void *blob, int node_list[], int count)
}
#endif
+/**
+ * Set up a new SPI slave for an fdt node
+ *
+ * @param blob Device tree blob
+ * @param node SPI peripheral node to use
+ * @return 0 if ok, -1 on error
+ */
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
+ unsigned int cs, unsigned int max_hz, unsigned int mode)
+{
+ struct spi_bus *bus;
+ unsigned int i;
+
+ for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) {
+ if (bus->node == node)
+ return spi_setup_slave(i, cs, max_hz, mode);
+ }
+
+ debug("%s: Failed to find bus node %d\n", __func__, node);
+ return NULL;
+}
+
/* Sadly there is no error return from this function */
void spi_init(void)
{
diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c
index 60e03a4..7bb91e5 100644
--- a/drivers/usb/musb/musb_hcd.c
+++ b/drivers/usb/musb/musb_hcd.c
@@ -1105,8 +1105,7 @@ int usb_lowlevel_init(int index, void **controller)
/* Configure all the endpoint FIFO's and start usb controller */
musbr = musb_cfg.regs;
- musb_configure_ep(&epinfo[0],
- sizeof(epinfo) / sizeof(struct musb_epinfo));
+ musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
musb_start();
/*
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
index e0b4217..e8a2ce0 100644
--- a/drivers/usb/musb/musb_udc.c
+++ b/drivers/usb/musb/musb_udc.c
@@ -894,8 +894,7 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
epinfo[id * 2].epsize = endpoint->rcv_packetSize;
}
- musb_configure_ep(&epinfo[0],
- sizeof(epinfo) / sizeof(struct musb_epinfo));
+ musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
} else {
if (debug_level > 0)
serial_printf("ERROR : %s endpoint request %d "
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 3e9ca11..8cfc3fa 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -82,6 +82,9 @@ typedef struct global_data {
unsigned long fdt_size; /* Space reserved for relocated FDT */
void **jt; /* jump table */
char env_buf[32]; /* buffer for getenv() before reloc. */
+#ifdef CONFIG_TRACE
+ void *trace_buff; /* The trace buffer */
+#endif
struct arch_global_data arch; /* architecture-specific data */
} gd_t;
#endif
diff --git a/include/common.h b/include/common.h
index 126891d..e5220cf 100644
--- a/include/common.h
+++ b/include/common.h
@@ -750,6 +750,10 @@ void irq_install_handler(int, interrupt_handler_t *, void *);
void irq_free_handler (int);
void reset_timer (void);
ulong get_timer (ulong base);
+
+/* Return value of monotonic microsecond timer */
+unsigned long timer_get_us(void);
+
void enable_interrupts (void);
int disable_interrupts (void);
diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index 2fefdc8..288ef8d 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -168,6 +168,13 @@
*/
#include <config_cmd_default.h>
+#define CONFIG_TRACE
+#define CONFIG_CMD_TRACE
+#define CONFIG_TRACE_BUFFER_SIZE (16 << 20)
+#define CONFIG_TRACE_EARLY_SIZE (8 << 20)
+#define CONFIG_TRACE_EARLY
+#define CONFIG_TRACE_EARLY_ADDR 0x01400000
+
#define CONFIG_CMD_BDI
#define CONFIG_CMD_BOOTD
#define CONFIG_CMD_CONSOLE
diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h
index 1632435..e2a096b 100644
--- a/include/configs/exynos5250-dt.h
+++ b/include/configs/exynos5250-dt.h
@@ -43,6 +43,14 @@
#define CONFIG_OF_CONTROL
#define CONFIG_OF_SEPARATE
+/* Allow tracing to be enabled */
+#define CONFIG_TRACE
+#define CONFIG_CMD_TRACE
+#define CONFIG_TRACE_BUFFER_SIZE (16 << 20)
+#define CONFIG_TRACE_EARLY_SIZE (8 << 20)
+#define CONFIG_TRACE_EARLY
+#define CONFIG_TRACE_EARLY_ADDR 0x50000000
+
/* Keep L2 Cache Disabled */
#define CONFIG_SYS_DCACHE_OFF
@@ -82,11 +90,19 @@
#define CONFIG_BAUDRATE 115200
#define EXYNOS5_DEFAULT_UART_OFFSET 0x010000
+/* Enable keyboard */
+#define CONFIG_CROS_EC /* CROS_EC protocol */
+#define CONFIG_CROS_EC_SPI /* Support CROS_EC over SPI */
+#define CONFIG_CROS_EC_I2C /* Support CROS_EC over I2C */
+#define CONFIG_CROS_EC_KEYB /* CROS_EC keyboard input */
+#define CONFIG_CMD_CROS_EC
+#define CONFIG_KEYBOARD
+
/* Console configuration */
#define CONFIG_CONSOLE_MUX
#define CONFIG_SYS_CONSOLE_IS_IN_ENV
#define EXYNOS_DEVICE_SETTINGS \
- "stdin=serial\0" \
+ "stdin=serial,cros-ec-keyb\0" \
"stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 788207d..98dd083 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -22,6 +22,19 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#ifdef FTRACE
+#define CONFIG_TRACE
+#define CONFIG_CMD_TRACE
+#define CONFIG_TRACE_BUFFER_SIZE (16 << 20)
+#define CONFIG_TRACE_EARLY_SIZE (8 << 20)
+#define CONFIG_TRACE_EARLY
+#define CONFIG_TRACE_EARLY_ADDR 0x00100000
+
+#endif
+
+#define CONFIG_BOOTSTAGE
+#define CONFIG_BOOTSTAGE_REPORT
+
/* Number of bits in a C 'long' on this architecture */
#define CONFIG_SANDBOX_BITS_PER_LONG 64
@@ -30,6 +43,8 @@
#define CONFIG_OF_LIBFDT
#define CONFIG_LMB
#define CONFIG_FIT
+#define CONFIG_FIT_SIGNATURE
+#define CONFIG_RSA
#define CONFIG_CMD_FDT
#define CONFIG_FS_FAT
diff --git a/include/cros_ec.h b/include/cros_ec.h
new file mode 100644
index 0000000..335d5b4
--- /dev/null
+++ b/include/cros_ec.h
@@ -0,0 +1,449 @@
+/*
+ * Chromium OS cros_ec driver
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _CROS_EC_H
+#define _CROS_EC_H
+
+#include <linux/compiler.h>
+#include <ec_commands.h>
+#include <fdtdec.h>
+#include <cros_ec_message.h>
+
+/* Which interface is the device on? */
+enum cros_ec_interface_t {
+ CROS_EC_IF_NONE,
+ CROS_EC_IF_SPI,
+ CROS_EC_IF_I2C,
+ CROS_EC_IF_LPC, /* Intel Low Pin Count interface */
+};
+
+/* Our configuration information */
+struct cros_ec_dev {
+ enum cros_ec_interface_t interface;
+ struct spi_slave *spi; /* Our SPI slave, if using SPI */
+ int node; /* Our node */
+ int parent_node; /* Our parent node (interface) */
+ unsigned int cs; /* Our chip select */
+ unsigned int addr; /* Device address (for I2C) */
+ unsigned int bus_num; /* Bus number (for I2C) */
+ unsigned int max_frequency; /* Maximum interface frequency */
+ struct fdt_gpio_state ec_int; /* GPIO used as EC interrupt line */
+ int cmd_version_is_supported; /* Device supports command versions */
+ int optimise_flash_write; /* Don't write erased flash blocks */
+
+ /*
+ * These two buffers will always be dword-aligned and include enough
+ * space for up to 7 word-alignment bytes also, so we can ensure that
+ * the body of the message is always dword-aligned (64-bit).
+ *
+ * We use this alignment to keep ARM and x86 happy. Probably word
+ * alignment would be OK, there might be a small performance advantage
+ * to using dword.
+ */
+ uint8_t din[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))]
+ __aligned(sizeof(int64_t));
+ uint8_t dout[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))]
+ __aligned(sizeof(int64_t));
+};
+
+/*
+ * Hard-code the number of columns we happen to know we have right now. It
+ * would be more correct to call cros_ec_info() at startup and determine the
+ * actual number of keyboard cols from there.
+ */
+#define CROS_EC_KEYSCAN_COLS 13
+
+/* Information returned by a key scan */
+struct mbkp_keyscan {
+ uint8_t data[CROS_EC_KEYSCAN_COLS];
+};
+
+/**
+ * Read the ID of the CROS-EC device
+ *
+ * The ID is a string identifying the CROS-EC device.
+ *
+ * @param dev CROS-EC device
+ * @param id Place to put the ID
+ * @param maxlen Maximum length of the ID field
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen);
+
+/**
+ * Read a keyboard scan from the CROS-EC device
+ *
+ * Send a message requesting a keyboard scan and return the result
+ *
+ * @param dev CROS-EC device
+ * @param scan Place to put the scan results
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan);
+
+/**
+ * Read which image is currently running on the CROS-EC device.
+ *
+ * @param dev CROS-EC device
+ * @param image Destination for image identifier
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_read_current_image(struct cros_ec_dev *dev,
+ enum ec_current_image *image);
+
+/**
+ * Read the hash of the CROS-EC device firmware.
+ *
+ * @param dev CROS-EC device
+ * @param hash Destination for hash information
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_read_hash(struct cros_ec_dev *dev,
+ struct ec_response_vboot_hash *hash);
+
+/**
+ * Send a reboot command to the CROS-EC device.
+ *
+ * Note that some reboot commands (such as EC_REBOOT_COLD) also reboot the AP.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Reboot command
+ * @param flags Flags for reboot command (EC_REBOOT_FLAG_*)
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
+ uint8_t flags);
+
+/**
+ * Check if the CROS-EC device has an interrupt pending.
+ *
+ * Read the status of the external interrupt connected to the CROS-EC device.
+ * If no external interrupt is configured, this always returns 1.
+ *
+ * @param dev CROS-EC device
+ * @return 0 if no interrupt is pending
+ */
+int cros_ec_interrupt_pending(struct cros_ec_dev *dev);
+
+enum {
+ CROS_EC_OK,
+ CROS_EC_ERR = 1,
+ CROS_EC_ERR_FDT_DECODE,
+ CROS_EC_ERR_CHECK_VERSION,
+ CROS_EC_ERR_READ_ID,
+ CROS_EC_ERR_DEV_INIT,
+};
+
+/**
+ * Set up the Chromium OS matrix keyboard protocol
+ *
+ * @param blob Device tree blob containing setup information
+ * @param cros_ecp Returns pointer to the cros_ec device, or NULL if none
+ * @return 0 if we got an cros_ec device and all is well (or no cros_ec is
+ * expected), -ve if we should have an cros_ec device but failed to find
+ * one, or init failed (-CROS_EC_ERR_...).
+ */
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp);
+
+/**
+ * Read information about the keyboard matrix
+ *
+ * @param dev CROS-EC device
+ * @param info Place to put the info structure
+ */
+int cros_ec_info(struct cros_ec_dev *dev,
+ struct ec_response_cros_ec_info *info);
+
+/**
+ * Read the host event flags
+ *
+ * @param dev CROS-EC device
+ * @param events_ptr Destination for event flags. Not changed on error.
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr);
+
+/**
+ * Clear the specified host event flags
+ *
+ * @param dev CROS-EC device
+ * @param events Event flags to clear
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events);
+
+/**
+ * Get/set flash protection
+ *
+ * @param dev CROS-EC device
+ * @param set_mask Mask of flags to set; if 0, just retrieves existing
+ * protection state without changing it.
+ * @param set_flags New flag values; only bits in set_mask are applied;
+ * ignored if set_mask=0.
+ * @param prot Destination for updated protection state from EC.
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_flash_protect(struct cros_ec_dev *dev,
+ uint32_t set_mask, uint32_t set_flags,
+ struct ec_response_flash_protect *resp);
+
+
+/**
+ * Run internal tests on the cros_ec interface.
+ *
+ * @param dev CROS-EC device
+ * @return 0 if ok, <0 if the test failed
+ */
+int cros_ec_test(struct cros_ec_dev *dev);
+
+/**
+ * Update the EC RW copy.
+ *
+ * @param dev CROS-EC device
+ * @param image the content to write
+ * @param imafge_size content length
+ * @return 0 if ok, <0 if the test failed
+ */
+int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
+ const uint8_t *image, int image_size);
+
+/**
+ * Return a pointer to the board's CROS-EC device
+ *
+ * This should be implemented by board files.
+ *
+ * @return pointer to CROS-EC device, or NULL if none is available
+ */
+struct cros_ec_dev *board_get_cros_ec_dev(void);
+
+
+/* Internal interfaces */
+int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob);
+int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob);
+int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Read information from the fdt for the i2c cros_ec interface
+ *
+ * @param dev CROS-EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 if we failed to read all required information
+ */
+int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Read information from the fdt for the spi cros_ec interface
+ *
+ * @param dev CROS-EC device
+ * @param blob Device tree blob
+ * @return 0 if ok, -1 if we failed to read all required information
+ */
+int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Check whether the LPC interface supports new-style commands.
+ *
+ * LPC has its own way of doing this, which involves checking LPC values
+ * visible to the host. Do this, and update dev->cmd_version_is_supported
+ * accordingly.
+ *
+ * @param dev CROS-EC device to check
+ */
+int cros_ec_lpc_check_version(struct cros_ec_dev *dev);
+
+/**
+ * Send a command to an I2C CROS-EC device and return the reply.
+ *
+ * This rather complicated function deals with sending both old-style and
+ * new-style commands. The old ones have just a command byte and arguments.
+ * The new ones have version, command, arg-len, [args], chksum so are 3 bytes
+ * longer.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Returns pointer to response data
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len);
+
+/**
+ * Send a command to a LPC CROS-EC device and return the reply.
+ *
+ * The device's internal input/output buffers are used.
+ *
+ * @param dev CROS-EC device
+ * @param cmd Command to send (EC_CMD_...)
+ * @param cmd_version Version of command to send (EC_VER_...)
+ * @param dout Output data (may be NULL If dout_len=0)
+ * @param dout_len Size of output data in bytes
+ * @param dinp Returns pointer to response data
+ * @param din_len Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len);
+
+int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+ const uint8_t *dout, int dout_len,
+ uint8_t **dinp, int din_len);
+
+/**
+ * Dump a block of data for a command.
+ *
+ * @param name Name for data (e.g. 'in', 'out')
+ * @param cmd Command number associated with data, or -1 for none
+ * @param data Data block to dump
+ * @param len Length of data block to dump
+ */
+void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len);
+
+/**
+ * Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data Data block to checksum
+ * @param size Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+int cros_ec_calc_checksum(const uint8_t *data, int size);
+
+/**
+ * Decode a flash region parameter
+ *
+ * @param argc Number of params remaining
+ * @param argv List of remaining parameters
+ * @return flash region (EC_FLASH_REGION_...) or -1 on error
+ */
+int cros_ec_decode_region(int argc, char * const argv[]);
+
+int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset,
+ uint32_t size);
+
+/**
+ * Read data from the flash
+ *
+ * Read an arbitrary amount of data from the EC flash, by repeatedly reading
+ * small blocks.
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to read for a particular region.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to read into
+ * @param offset Offset within flash to read from
+ * @param size Number of bytes to read
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
+ uint32_t size);
+
+/**
+ * Write data to the flash
+ *
+ * Write an arbitrary amount of data to the EC flash, by repeatedly writing
+ * small blocks.
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to write for a particular region.
+ *
+ * Attempting to write to the region where the EC is currently running from
+ * will result in an error.
+ *
+ * @param dev CROS-EC device
+ * @param data Pointer to data buffer to write
+ * @param offset Offset within flash to write to.
+ * @param size Number of bytes to write
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
+ uint32_t offset, uint32_t size);
+
+/**
+ * Obtain position and size of a flash region
+ *
+ * @param dev CROS-EC device
+ * @param region Flash region to query
+ * @param offset Returns offset of flash region in EC flash
+ * @param size Returns size of flash region
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
+ uint32_t *offset, uint32_t *size);
+
+/**
+ * Read/write VbNvContext from/to a CROS-EC device.
+ *
+ * @param dev CROS-EC device
+ * @param block Buffer of VbNvContext to be read/write
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block);
+int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block);
+
+/**
+ * Read the version information for the EC images
+ *
+ * @param dev CROS-EC device
+ * @param versionp This is set to point to the version information
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_version(struct cros_ec_dev *dev,
+ struct ec_response_get_version **versionp);
+
+/**
+ * Read the build information for the EC
+ *
+ * @param dev CROS-EC device
+ * @param versionp This is set to point to the build string
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp);
+
+/**
+ * Switch on/off a LDO / FET.
+ *
+ * @param dev CROS-EC device
+ * @param index index of the LDO/FET to switch
+ * @param state new state of the LDO/FET : EC_LDO_STATE_ON|OFF
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state);
+
+/**
+ * Read back a LDO / FET current state.
+ *
+ * @param dev CROS-EC device
+ * @param index index of the LDO/FET to switch
+ * @param state current state of the LDO/FET : EC_LDO_STATE_ON|OFF
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state);
+#endif
diff --git a/include/cros_ec_message.h b/include/cros_ec_message.h
new file mode 100644
index 0000000..a2421c7
--- /dev/null
+++ b/include/cros_ec_message.h
@@ -0,0 +1,44 @@
+/*
+ * Chromium OS Matrix Keyboard Message Protocol definitions
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _CROS_MESSAGE_H
+#define _CROS_MESSAGE_H
+
+/*
+ * Command interface between EC and AP, for LPC, I2C and SPI interfaces.
+ *
+ * This is copied from the Chromium OS Open Source Embedded Controller code.
+ */
+enum {
+ /* The header byte, which follows the preamble */
+ MSG_HEADER = 0xec,
+
+ MSG_HEADER_BYTES = 3,
+ MSG_TRAILER_BYTES = 2,
+ MSG_PROTO_BYTES = MSG_HEADER_BYTES + MSG_TRAILER_BYTES,
+
+ /* Max length of messages */
+ MSG_BYTES = EC_HOST_PARAM_SIZE + MSG_PROTO_BYTES,
+};
+
+#endif
diff --git a/include/ec_commands.h b/include/ec_commands.h
new file mode 100644
index 0000000..12811cc
--- /dev/null
+++ b/include/ec_commands.h
@@ -0,0 +1,1440 @@
+/* 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.
+ */
+
+/* Host communication command constants for Chrome EC */
+
+#ifndef __CROS_EC_COMMANDS_H
+#define __CROS_EC_COMMANDS_H
+
+/*
+ * Protocol overview
+ *
+ * request: CMD [ P0 P1 P2 ... Pn S ]
+ * response: ERR [ P0 P1 P2 ... Pn S ]
+ *
+ * where the bytes are defined as follow :
+ * - CMD is the command code. (defined by EC_CMD_ constants)
+ * - ERR is the error code. (defined by EC_RES_ constants)
+ * - Px is the optional payload.
+ * it is not sent if the error code is not success.
+ * (defined by ec_params_ and ec_response_ structures)
+ * - S is the checksum which is the sum of all payload bytes.
+ *
+ * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD
+ * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM.
+ * On I2C, all bytes are sent serially in the same message.
+ */
+
+/* Current version of this protocol */
+#define EC_PROTO_VERSION 0x00000002
+
+/* Command version mask */
+#define EC_VER_MASK(version) (1UL << (version))
+
+/* I/O addresses for ACPI commands */
+#define EC_LPC_ADDR_ACPI_DATA 0x62
+#define EC_LPC_ADDR_ACPI_CMD 0x66
+
+/* I/O addresses for host command */
+#define EC_LPC_ADDR_HOST_DATA 0x200
+#define EC_LPC_ADDR_HOST_CMD 0x204
+
+/* I/O addresses for host command args and params */
+#define EC_LPC_ADDR_HOST_ARGS 0x800
+#define EC_LPC_ADDR_HOST_PARAM 0x804
+#define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */
+
+/* I/O addresses for host command params, old interface */
+#define EC_LPC_ADDR_OLD_PARAM 0x880
+#define EC_OLD_PARAM_SIZE 0x080 /* Size of param area in bytes */
+
+/* EC command register bit functions */
+#define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */
+#define EC_LPC_CMDR_PENDING (1 << 1) /* Write pending to EC */
+#define EC_LPC_CMDR_BUSY (1 << 2) /* EC is busy processing a command */
+#define EC_LPC_CMDR_CMD (1 << 3) /* Last host write was a command */
+#define EC_LPC_CMDR_ACPI_BRST (1 << 4) /* Burst mode (not used) */
+#define EC_LPC_CMDR_SCI (1 << 5) /* SCI event is pending */
+#define EC_LPC_CMDR_SMI (1 << 6) /* SMI event is pending */
+
+#define EC_LPC_ADDR_MEMMAP 0x900
+#define EC_MEMMAP_SIZE 255 /* ACPI IO buffer max is 255 bytes */
+#define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */
+
+/* The offset address of each type of data in mapped memory. */
+#define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors */
+#define EC_MEMMAP_FAN 0x10 /* Fan speeds */
+#define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* Temp sensors (second set) */
+#define EC_MEMMAP_ID 0x20 /* 'E' 'C' */
+#define EC_MEMMAP_ID_VERSION 0x22 /* Version of data in 0x20 - 0x2f */
+#define EC_MEMMAP_THERMAL_VERSION 0x23 /* Version of data in 0x00 - 0x1f */
+#define EC_MEMMAP_BATTERY_VERSION 0x24 /* Version of data in 0x40 - 0x7f */
+#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */
+#define EC_MEMMAP_EVENTS_VERSION 0x26 /* Version of data in 0x34 - 0x3f */
+#define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host command interface flags */
+#define EC_MEMMAP_SWITCHES 0x30
+#define EC_MEMMAP_HOST_EVENTS 0x34
+#define EC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */
+#define EC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */
+#define EC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */
+#define EC_MEMMAP_BATT_FLAG 0x4c /* Battery State, defined below */
+#define EC_MEMMAP_BATT_DCAP 0x50 /* Battery Design Capacity */
+#define EC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */
+#define EC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */
+#define EC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */
+#define EC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */
+#define EC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */
+#define EC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */
+#define EC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */
+
+/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */
+#define EC_TEMP_SENSOR_ENTRIES 16
+/*
+ * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B.
+ *
+ * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2.
+ */
+#define EC_TEMP_SENSOR_B_ENTRIES 8
+#define EC_TEMP_SENSOR_NOT_PRESENT 0xff
+#define EC_TEMP_SENSOR_ERROR 0xfe
+#define EC_TEMP_SENSOR_NOT_POWERED 0xfd
+#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc
+/*
+ * The offset of temperature value stored in mapped memory. This allows
+ * reporting a temperature range of 200K to 454K = -73C to 181C.
+ */
+#define EC_TEMP_SENSOR_OFFSET 200
+
+#define EC_FAN_SPEED_ENTRIES 4 /* Number of fans at EC_MEMMAP_FAN */
+#define EC_FAN_SPEED_NOT_PRESENT 0xffff /* Entry not present */
+#define EC_FAN_SPEED_STALLED 0xfffe /* Fan stalled */
+
+/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */
+#define EC_BATT_FLAG_AC_PRESENT 0x01
+#define EC_BATT_FLAG_BATT_PRESENT 0x02
+#define EC_BATT_FLAG_DISCHARGING 0x04
+#define EC_BATT_FLAG_CHARGING 0x08
+#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10
+
+/* Switch flags at EC_MEMMAP_SWITCHES */
+#define EC_SWITCH_LID_OPEN 0x01
+#define EC_SWITCH_POWER_BUTTON_PRESSED 0x02
+#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04
+/* Recovery requested via keyboard */
+#define EC_SWITCH_KEYBOARD_RECOVERY 0x08
+/* Recovery requested via dedicated signal (from servo board) */
+#define EC_SWITCH_DEDICATED_RECOVERY 0x10
+/* Was fake developer mode switch; now unused. Remove in next refactor. */
+#define EC_SWITCH_IGNORE0 0x20
+
+/* Host command interface flags */
+/* Host command interface supports LPC args (LPC interface only) */
+#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED 0x01
+
+/* Wireless switch flags */
+#define EC_WIRELESS_SWITCH_WLAN 0x01
+#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02
+
+/*
+ * This header file is used in coreboot both in C and ACPI code. The ACPI code
+ * is pre-processed to handle constants but the ASL compiler is unable to
+ * handle actual C code so keep it separate.
+ */
+#ifndef __ACPI__
+
+/*
+ * Define __packed if someone hasn't beat us to it. Linux kernel style
+ * checking prefers __packed over __attribute__((packed)).
+ */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* LPC command status byte masks */
+/* EC has written a byte in the data register and host hasn't read it yet */
+#define EC_LPC_STATUS_TO_HOST 0x01
+/* Host has written a command/data byte and the EC hasn't read it yet */
+#define EC_LPC_STATUS_FROM_HOST 0x02
+/* EC is processing a command */
+#define EC_LPC_STATUS_PROCESSING 0x04
+/* Last write to EC was a command, not data */
+#define EC_LPC_STATUS_LAST_CMD 0x08
+/* EC is in burst mode. Unsupported by Chrome EC, so this bit is never set */
+#define EC_LPC_STATUS_BURST_MODE 0x10
+/* SCI event is pending (requesting SCI query) */
+#define EC_LPC_STATUS_SCI_PENDING 0x20
+/* SMI event is pending (requesting SMI query) */
+#define EC_LPC_STATUS_SMI_PENDING 0x40
+/* (reserved) */
+#define EC_LPC_STATUS_RESERVED 0x80
+
+/*
+ * EC is busy. This covers both the EC processing a command, and the host has
+ * written a new command but the EC hasn't picked it up yet.
+ */
+#define EC_LPC_STATUS_BUSY_MASK \
+ (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING)
+
+/* Host command response codes */
+enum ec_status {
+ EC_RES_SUCCESS = 0,
+ EC_RES_INVALID_COMMAND = 1,
+ EC_RES_ERROR = 2,
+ EC_RES_INVALID_PARAM = 3,
+ EC_RES_ACCESS_DENIED = 4,
+ EC_RES_INVALID_RESPONSE = 5,
+ EC_RES_INVALID_VERSION = 6,
+ EC_RES_INVALID_CHECKSUM = 7,
+ EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */
+ EC_RES_UNAVAILABLE = 9, /* No response available */
+ EC_RES_TIMEOUT = 10, /* We got a timeout */
+ EC_RES_OVERFLOW = 11, /* Table / data overflow */
+};
+
+/*
+ * Host event codes. Note these are 1-based, not 0-based, because ACPI query
+ * EC command uses code 0 to mean "no event pending". We explicitly specify
+ * each value in the enum listing so they won't change if we delete/insert an
+ * item or rearrange the list (it needs to be stable across platforms, not
+ * just within a single compiled instance).
+ */
+enum host_event_code {
+ EC_HOST_EVENT_LID_CLOSED = 1,
+ EC_HOST_EVENT_LID_OPEN = 2,
+ EC_HOST_EVENT_POWER_BUTTON = 3,
+ EC_HOST_EVENT_AC_CONNECTED = 4,
+ EC_HOST_EVENT_AC_DISCONNECTED = 5,
+ EC_HOST_EVENT_BATTERY_LOW = 6,
+ EC_HOST_EVENT_BATTERY_CRITICAL = 7,
+ EC_HOST_EVENT_BATTERY = 8,
+ EC_HOST_EVENT_THERMAL_THRESHOLD = 9,
+ EC_HOST_EVENT_THERMAL_OVERLOAD = 10,
+ EC_HOST_EVENT_THERMAL = 11,
+ EC_HOST_EVENT_USB_CHARGER = 12,
+ EC_HOST_EVENT_KEY_PRESSED = 13,
+ /*
+ * EC has finished initializing the host interface. The host can check
+ * for this event following sending a EC_CMD_REBOOT_EC command to
+ * determine when the EC is ready to accept subsequent commands.
+ */
+ EC_HOST_EVENT_INTERFACE_READY = 14,
+ /* Keyboard recovery combo has been pressed */
+ EC_HOST_EVENT_KEYBOARD_RECOVERY = 15,
+
+ /* Shutdown due to thermal overload */
+ EC_HOST_EVENT_THERMAL_SHUTDOWN = 16,
+ /* Shutdown due to battery level too low */
+ EC_HOST_EVENT_BATTERY_SHUTDOWN = 17,
+
+ /*
+ * The high bit of the event mask is not used as a host event code. If
+ * it reads back as set, then the entire event mask should be
+ * considered invalid by the host. This can happen when reading the
+ * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is
+ * not initialized on the EC, or improperly configured on the host.
+ */
+ EC_HOST_EVENT_INVALID = 32
+};
+/* Host event mask */
+#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1))
+
+/* Arguments at EC_LPC_ADDR_HOST_ARGS */
+struct ec_lpc_host_args {
+ uint8_t flags;
+ uint8_t command_version;
+ uint8_t data_size;
+ /*
+ * Checksum; sum of command + flags + command_version + data_size +
+ * all params/response data bytes.
+ */
+ uint8_t checksum;
+} __packed;
+
+/* Flags for ec_lpc_host_args.flags */
+/*
+ * Args are from host. Data area at EC_LPC_ADDR_HOST_PARAM contains command
+ * params.
+ *
+ * If EC gets a command and this flag is not set, this is an old-style command.
+ * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with
+ * unknown length. EC must respond with an old-style response (that is,
+ * withouth setting EC_HOST_ARGS_FLAG_TO_HOST).
+ */
+#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01
+/*
+ * Args are from EC. Data area at EC_LPC_ADDR_HOST_PARAM contains response.
+ *
+ * If EC responds to a command and this flag is not set, this is an old-style
+ * response. Command version is 0 and response data from EC is at
+ * EC_LPC_ADDR_OLD_PARAM with unknown length.
+ */
+#define EC_HOST_ARGS_FLAG_TO_HOST 0x02
+
+/*
+ * Notes on commands:
+ *
+ * Each command is an 8-byte command value. Commands which take params or
+ * return response data specify structs for that data. If no struct is
+ * specified, the command does not input or output data, respectively.
+ * Parameter/response length is implicit in the structs. Some underlying
+ * communication protocols (I2C, SPI) may add length or checksum headers, but
+ * those are implementation-dependent and not defined here.
+ */
+
+/*****************************************************************************/
+/* General / test commands */
+
+/*
+ * Get protocol version, used to deal with non-backward compatible protocol
+ * changes.
+ */
+#define EC_CMD_PROTO_VERSION 0x00
+
+struct ec_response_proto_version {
+ uint32_t version;
+} __packed;
+
+/*
+ * Hello. This is a simple command to test the EC is responsive to
+ * commands.
+ */
+#define EC_CMD_HELLO 0x01
+
+struct ec_params_hello {
+ uint32_t in_data; /* Pass anything here */
+} __packed;
+
+struct ec_response_hello {
+ uint32_t out_data; /* Output will be in_data + 0x01020304 */
+} __packed;
+
+/* Get version number */
+#define EC_CMD_GET_VERSION 0x02
+
+enum ec_current_image {
+ EC_IMAGE_UNKNOWN = 0,
+ EC_IMAGE_RO,
+ EC_IMAGE_RW
+};
+
+struct ec_response_get_version {
+ /* Null-terminated version strings for RO, RW */
+ char version_string_ro[32];
+ char version_string_rw[32];
+ char reserved[32]; /* Was previously RW-B string */
+ uint32_t current_image; /* One of ec_current_image */
+} __packed;
+
+/* Read test */
+#define EC_CMD_READ_TEST 0x03
+
+struct ec_params_read_test {
+ uint32_t offset; /* Starting value for read buffer */
+ uint32_t size; /* Size to read in bytes */
+} __packed;
+
+struct ec_response_read_test {
+ uint32_t data[32];
+} __packed;
+
+/*
+ * Get build information
+ *
+ * Response is null-terminated string.
+ */
+#define EC_CMD_GET_BUILD_INFO 0x04
+
+/* Get chip info */
+#define EC_CMD_GET_CHIP_INFO 0x05
+
+struct ec_response_get_chip_info {
+ /* Null-terminated strings */
+ char vendor[32];
+ char name[32];
+ char revision[32]; /* Mask version */
+} __packed;
+
+/* Get board HW version */
+#define EC_CMD_GET_BOARD_VERSION 0x06
+
+struct ec_response_board_version {
+ uint16_t board_version; /* A monotonously incrementing number. */
+} __packed;
+
+/*
+ * Read memory-mapped data.
+ *
+ * This is an alternate interface to memory-mapped data for bus protocols
+ * which don't support direct-mapped memory - I2C, SPI, etc.
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_READ_MEMMAP 0x07
+
+struct ec_params_read_memmap {
+ uint8_t offset; /* Offset in memmap (EC_MEMMAP_*) */
+ uint8_t size; /* Size to read in bytes */
+} __packed;
+
+/* Read versions supported for a command */
+#define EC_CMD_GET_CMD_VERSIONS 0x08
+
+struct ec_params_get_cmd_versions {
+ uint8_t cmd; /* Command to check */
+} __packed;
+
+struct ec_response_get_cmd_versions {
+ /*
+ * Mask of supported versions; use EC_VER_MASK() to compare with a
+ * desired version.
+ */
+ uint32_t version_mask;
+} __packed;
+
+/*
+ * Check EC communcations status (busy). This is needed on i2c/spi but not
+ * on lpc since it has its own out-of-band busy indicator.
+ *
+ * lpc must read the status from the command register. Attempting this on
+ * lpc will overwrite the args/parameter space and corrupt its data.
+ */
+#define EC_CMD_GET_COMMS_STATUS 0x09
+
+/* Avoid using ec_status which is for return values */
+enum ec_comms_status {
+ EC_COMMS_STATUS_PROCESSING = 1 << 0, /* Processing cmd */
+};
+
+struct ec_response_get_comms_status {
+ uint32_t flags; /* Mask of enum ec_comms_status */
+} __packed;
+
+
+/*****************************************************************************/
+/* Flash commands */
+
+/* Get flash info */
+#define EC_CMD_FLASH_INFO 0x10
+
+struct ec_response_flash_info {
+ /* Usable flash size, in bytes */
+ uint32_t flash_size;
+ /*
+ * Write block size. Write offset and size must be a multiple
+ * of this.
+ */
+ uint32_t write_block_size;
+ /*
+ * Erase block size. Erase offset and size must be a multiple
+ * of this.
+ */
+ uint32_t erase_block_size;
+ /*
+ * Protection block size. Protection offset and size must be a
+ * multiple of this.
+ */
+ uint32_t protect_block_size;
+} __packed;
+
+/*
+ * Read flash
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_FLASH_READ 0x11
+
+struct ec_params_flash_read {
+ uint32_t offset; /* Byte offset to read */
+ uint32_t size; /* Size to read in bytes */
+} __packed;
+
+/* Write flash */
+#define EC_CMD_FLASH_WRITE 0x12
+
+struct ec_params_flash_write {
+ uint32_t offset; /* Byte offset to write */
+ uint32_t size; /* Size to write in bytes */
+ /*
+ * Data to write. Could really use EC_PARAM_SIZE - 8, but tidiest to
+ * use a power of 2 so writes stay aligned.
+ */
+ uint8_t data[64];
+} __packed;
+
+/* Erase flash */
+#define EC_CMD_FLASH_ERASE 0x13
+
+struct ec_params_flash_erase {
+ uint32_t offset; /* Byte offset to erase */
+ uint32_t size; /* Size to erase in bytes */
+} __packed;
+
+/*
+ * Get/set flash protection.
+ *
+ * If mask!=0, sets/clear the requested bits of flags. Depending on the
+ * firmware write protect GPIO, not all flags will take effect immediately;
+ * some flags require a subsequent hard reset to take effect. Check the
+ * returned flags bits to see what actually happened.
+ *
+ * If mask=0, simply returns the current flags state.
+ */
+#define EC_CMD_FLASH_PROTECT 0x15
+#define EC_VER_FLASH_PROTECT 1 /* Command version 1 */
+
+/* Flags for flash protection */
+/* RO flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RO_AT_BOOT (1 << 0)
+/*
+ * RO flash code protected now. If this bit is set, at-boot status cannot
+ * be changed.
+ */
+#define EC_FLASH_PROTECT_RO_NOW (1 << 1)
+/* Entire flash code protected now, until reboot. */
+#define EC_FLASH_PROTECT_ALL_NOW (1 << 2)
+/* Flash write protect GPIO is asserted now */
+#define EC_FLASH_PROTECT_GPIO_ASSERTED (1 << 3)
+/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */
+#define EC_FLASH_PROTECT_ERROR_STUCK (1 << 4)
+/*
+ * Error - flash protection is in inconsistent state. At least one bank of
+ * flash which should be protected is not protected. Usually fixed by
+ * re-requesting the desired flags, or by a hard reset if that fails.
+ */
+#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5)
+/* Entile flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_ALL_AT_BOOT (1 << 6)
+
+struct ec_params_flash_protect {
+ uint32_t mask; /* Bits in flags to apply */
+ uint32_t flags; /* New flags to apply */
+} __packed;
+
+struct ec_response_flash_protect {
+ /* Current value of flash protect flags */
+ uint32_t flags;
+ /*
+ * Flags which are valid on this platform. This allows the caller
+ * to distinguish between flags which aren't set vs. flags which can't
+ * be set on this platform.
+ */
+ uint32_t valid_flags;
+ /* Flags which can be changed given the current protection state */
+ uint32_t writable_flags;
+} __packed;
+
+/*
+ * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash
+ * write protect. These commands may be reused with version > 0.
+ */
+
+/* Get the region offset/size */
+#define EC_CMD_FLASH_REGION_INFO 0x16
+#define EC_VER_FLASH_REGION_INFO 1
+
+enum ec_flash_region {
+ /* Region which holds read-only EC image */
+ EC_FLASH_REGION_RO,
+ /* Region which holds rewritable EC image */
+ EC_FLASH_REGION_RW,
+ /*
+ * Region which should be write-protected in the factory (a superset of
+ * EC_FLASH_REGION_RO)
+ */
+ EC_FLASH_REGION_WP_RO,
+};
+
+struct ec_params_flash_region_info {
+ uint32_t region; /* enum ec_flash_region */
+} __packed;
+
+struct ec_response_flash_region_info {
+ uint32_t offset;
+ uint32_t size;
+} __packed;
+
+/* Read/write VbNvContext */
+#define EC_CMD_VBNV_CONTEXT 0x17
+#define EC_VER_VBNV_CONTEXT 1
+#define EC_VBNV_BLOCK_SIZE 16
+
+enum ec_vbnvcontext_op {
+ EC_VBNV_CONTEXT_OP_READ,
+ EC_VBNV_CONTEXT_OP_WRITE,
+};
+
+struct ec_params_vbnvcontext {
+ uint32_t op;
+ uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+struct ec_response_vbnvcontext {
+ uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+/*****************************************************************************/
+/* PWM commands */
+
+/* Get fan target RPM */
+#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20
+
+struct ec_response_pwm_get_fan_rpm {
+ uint32_t rpm;
+} __packed;
+
+/* Set target fan RPM */
+#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21
+
+struct ec_params_pwm_set_fan_target_rpm {
+ uint32_t rpm;
+} __packed;
+
+/* Get keyboard backlight */
+#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22
+
+struct ec_response_pwm_get_keyboard_backlight {
+ uint8_t percent;
+ uint8_t enabled;
+} __packed;
+
+/* Set keyboard backlight */
+#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23
+
+struct ec_params_pwm_set_keyboard_backlight {
+ uint8_t percent;
+} __packed;
+
+/* Set target fan PWM duty cycle */
+#define EC_CMD_PWM_SET_FAN_DUTY 0x24
+
+struct ec_params_pwm_set_fan_duty {
+ uint32_t percent;
+} __packed;
+
+/*****************************************************************************/
+/*
+ * Lightbar commands. This looks worse than it is. Since we only use one HOST
+ * command to say "talk to the lightbar", we put the "and tell it to do X" part
+ * into a subcommand. We'll make separate structs for subcommands with
+ * different input args, so that we know how much to expect.
+ */
+#define EC_CMD_LIGHTBAR_CMD 0x28
+
+struct rgb_s {
+ uint8_t r, g, b;
+};
+
+#define LB_BATTERY_LEVELS 4
+/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a
+ * host command, but the alignment is the same regardless. Keep it that way.
+ */
+struct lightbar_params {
+ /* Timing */
+ int google_ramp_up;
+ int google_ramp_down;
+ int s3s0_ramp_up;
+ int s0_tick_delay[2]; /* AC=0/1 */
+ int s0a_tick_delay[2]; /* AC=0/1 */
+ int s0s3_ramp_down;
+ int s3_sleep_for;
+ int s3_ramp_up;
+ int s3_ramp_down;
+
+ /* Oscillation */
+ uint8_t new_s0;
+ uint8_t osc_min[2]; /* AC=0/1 */
+ uint8_t osc_max[2]; /* AC=0/1 */
+ uint8_t w_ofs[2]; /* AC=0/1 */
+
+ /* Brightness limits based on the backlight and AC. */
+ uint8_t bright_bl_off_fixed[2]; /* AC=0/1 */
+ uint8_t bright_bl_on_min[2]; /* AC=0/1 */
+ uint8_t bright_bl_on_max[2]; /* AC=0/1 */
+
+ /* Battery level thresholds */
+ uint8_t battery_threshold[LB_BATTERY_LEVELS - 1];
+
+ /* Map [AC][battery_level] to color index */
+ uint8_t s0_idx[2][LB_BATTERY_LEVELS]; /* AP is running */
+ uint8_t s3_idx[2][LB_BATTERY_LEVELS]; /* AP is sleeping */
+
+ /* Color palette */
+ struct rgb_s color[8]; /* 0-3 are Google colors */
+} __packed;
+
+struct ec_params_lightbar {
+ uint8_t cmd; /* Command (see enum lightbar_command) */
+ union {
+ struct {
+ /* no args */
+ } dump, off, on, init, get_seq, get_params;
+
+ struct num {
+ uint8_t num;
+ } brightness, seq, demo;
+
+ struct reg {
+ uint8_t ctrl, reg, value;
+ } reg;
+
+ struct rgb {
+ uint8_t led, red, green, blue;
+ } rgb;
+
+ struct lightbar_params set_params;
+ };
+} __packed;
+
+struct ec_response_lightbar {
+ union {
+ struct dump {
+ struct {
+ uint8_t reg;
+ uint8_t ic0;
+ uint8_t ic1;
+ } vals[23];
+ } dump;
+
+ struct get_seq {
+ uint8_t num;
+ } get_seq;
+
+ struct lightbar_params get_params;
+
+ struct {
+ /* no return params */
+ } off, on, init, brightness, seq, reg, rgb, demo, set_params;
+ };
+} __packed;
+
+/* Lightbar commands */
+enum lightbar_command {
+ LIGHTBAR_CMD_DUMP = 0,
+ LIGHTBAR_CMD_OFF = 1,
+ LIGHTBAR_CMD_ON = 2,
+ LIGHTBAR_CMD_INIT = 3,
+ LIGHTBAR_CMD_BRIGHTNESS = 4,
+ LIGHTBAR_CMD_SEQ = 5,
+ LIGHTBAR_CMD_REG = 6,
+ LIGHTBAR_CMD_RGB = 7,
+ LIGHTBAR_CMD_GET_SEQ = 8,
+ LIGHTBAR_CMD_DEMO = 9,
+ LIGHTBAR_CMD_GET_PARAMS = 10,
+ LIGHTBAR_CMD_SET_PARAMS = 11,
+ LIGHTBAR_NUM_CMDS
+};
+
+/*****************************************************************************/
+/* Verified boot commands */
+
+/*
+ * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be
+ * reused for other purposes with version > 0.
+ */
+
+/* Verified boot hash command */
+#define EC_CMD_VBOOT_HASH 0x2A
+
+struct ec_params_vboot_hash {
+ uint8_t cmd; /* enum ec_vboot_hash_cmd */
+ uint8_t hash_type; /* enum ec_vboot_hash_type */
+ uint8_t nonce_size; /* Nonce size; may be 0 */
+ uint8_t reserved0; /* Reserved; set 0 */
+ uint32_t offset; /* Offset in flash to hash */
+ uint32_t size; /* Number of bytes to hash */
+ uint8_t nonce_data[64]; /* Nonce data; ignored if nonce_size=0 */
+} __packed;
+
+struct ec_response_vboot_hash {
+ uint8_t status; /* enum ec_vboot_hash_status */
+ uint8_t hash_type; /* enum ec_vboot_hash_type */
+ uint8_t digest_size; /* Size of hash digest in bytes */
+ uint8_t reserved0; /* Ignore; will be 0 */
+ uint32_t offset; /* Offset in flash which was hashed */
+ uint32_t size; /* Number of bytes hashed */
+ uint8_t hash_digest[64]; /* Hash digest data */
+} __packed;
+
+enum ec_vboot_hash_cmd {
+ EC_VBOOT_HASH_GET = 0, /* Get current hash status */
+ EC_VBOOT_HASH_ABORT = 1, /* Abort calculating current hash */
+ EC_VBOOT_HASH_START = 2, /* Start computing a new hash */
+ EC_VBOOT_HASH_RECALC = 3, /* Synchronously compute a new hash */
+};
+
+enum ec_vboot_hash_type {
+ EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */
+};
+
+enum ec_vboot_hash_status {
+ EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */
+ EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */
+ EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */
+};
+
+/*
+ * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC.
+ * If one of these is specified, the EC will automatically update offset and
+ * size to the correct values for the specified image (RO or RW).
+ */
+#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe
+#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd
+
+/*****************************************************************************/
+/* USB charging control commands */
+
+/* Set USB port charging mode */
+#define EC_CMD_USB_CHARGE_SET_MODE 0x30
+
+struct ec_params_usb_charge_set_mode {
+ uint8_t usb_port_id;
+ uint8_t mode;
+} __packed;
+
+/*****************************************************************************/
+/* Persistent storage for host */
+
+/* Maximum bytes that can be read/written in a single command */
+#define EC_PSTORE_SIZE_MAX 64
+
+/* Get persistent storage info */
+#define EC_CMD_PSTORE_INFO 0x40
+
+struct ec_response_pstore_info {
+ /* Persistent storage size, in bytes */
+ uint32_t pstore_size;
+ /* Access size; read/write offset and size must be a multiple of this */
+ uint32_t access_size;
+} __packed;
+
+/*
+ * Read persistent storage
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_PSTORE_READ 0x41
+
+struct ec_params_pstore_read {
+ uint32_t offset; /* Byte offset to read */
+ uint32_t size; /* Size to read in bytes */
+} __packed;
+
+/* Write persistent storage */
+#define EC_CMD_PSTORE_WRITE 0x42
+
+struct ec_params_pstore_write {
+ uint32_t offset; /* Byte offset to write */
+ uint32_t size; /* Size to write in bytes */
+ uint8_t data[EC_PSTORE_SIZE_MAX];
+} __packed;
+
+/*****************************************************************************/
+/* Real-time clock */
+
+/* RTC params and response structures */
+struct ec_params_rtc {
+ uint32_t time;
+} __packed;
+
+struct ec_response_rtc {
+ uint32_t time;
+} __packed;
+
+/* These use ec_response_rtc */
+#define EC_CMD_RTC_GET_VALUE 0x44
+#define EC_CMD_RTC_GET_ALARM 0x45
+
+/* These all use ec_params_rtc */
+#define EC_CMD_RTC_SET_VALUE 0x46
+#define EC_CMD_RTC_SET_ALARM 0x47
+
+/*****************************************************************************/
+/* Port80 log access */
+
+/* Get last port80 code from previous boot */
+#define EC_CMD_PORT80_LAST_BOOT 0x48
+
+struct ec_response_port80_last_boot {
+ uint16_t code;
+} __packed;
+
+/*****************************************************************************/
+/* Thermal engine commands */
+
+/* Set thershold value */
+#define EC_CMD_THERMAL_SET_THRESHOLD 0x50
+
+struct ec_params_thermal_set_threshold {
+ uint8_t sensor_type;
+ uint8_t threshold_id;
+ uint16_t value;
+} __packed;
+
+/* Get threshold value */
+#define EC_CMD_THERMAL_GET_THRESHOLD 0x51
+
+struct ec_params_thermal_get_threshold {
+ uint8_t sensor_type;
+ uint8_t threshold_id;
+} __packed;
+
+struct ec_response_thermal_get_threshold {
+ uint16_t value;
+} __packed;
+
+/* Toggle automatic fan control */
+#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52
+
+/* Get TMP006 calibration data */
+#define EC_CMD_TMP006_GET_CALIBRATION 0x53
+
+struct ec_params_tmp006_get_calibration {
+ uint8_t index;
+} __packed;
+
+struct ec_response_tmp006_get_calibration {
+ float s0;
+ float b0;
+ float b1;
+ float b2;
+} __packed;
+
+/* Set TMP006 calibration data */
+#define EC_CMD_TMP006_SET_CALIBRATION 0x54
+
+struct ec_params_tmp006_set_calibration {
+ uint8_t index;
+ uint8_t reserved[3]; /* Reserved; set 0 */
+ float s0;
+ float b0;
+ float b1;
+ float b2;
+} __packed;
+
+/*****************************************************************************/
+/* CROS_EC - Matrix KeyBoard Protocol */
+
+/*
+ * Read key state
+ *
+ * Returns raw data for keyboard cols; see ec_response_cros_ec_info.cols for
+ * expected response size.
+ */
+#define EC_CMD_CROS_EC_STATE 0x60
+
+/* Provide information about the matrix : number of rows and columns */
+#define EC_CMD_CROS_EC_INFO 0x61
+
+struct ec_response_cros_ec_info {
+ uint32_t rows;
+ uint32_t cols;
+ uint8_t switches;
+} __packed;
+
+/* Simulate key press */
+#define EC_CMD_CROS_EC_SIMULATE_KEY 0x62
+
+struct ec_params_cros_ec_simulate_key {
+ uint8_t col;
+ uint8_t row;
+ uint8_t pressed;
+} __packed;
+
+/* Configure keyboard scanning */
+#define EC_CMD_CROS_EC_SET_CONFIG 0x64
+#define EC_CMD_CROS_EC_GET_CONFIG 0x65
+
+/* flags */
+enum cros_ec_config_flags {
+ EC_CROS_EC_FLAGS_ENABLE = 1, /* Enable keyboard scanning */
+};
+
+enum cros_ec_config_valid {
+ EC_CROS_EC_VALID_SCAN_PERIOD = 1 << 0,
+ EC_CROS_EC_VALID_POLL_TIMEOUT = 1 << 1,
+ EC_CROS_EC_VALID_MIN_POST_SCAN_DELAY = 1 << 3,
+ EC_CROS_EC_VALID_OUTPUT_SETTLE = 1 << 4,
+ EC_CROS_EC_VALID_DEBOUNCE_DOWN = 1 << 5,
+ EC_CROS_EC_VALID_DEBOUNCE_UP = 1 << 6,
+ EC_CROS_EC_VALID_FIFO_MAX_DEPTH = 1 << 7,
+};
+
+/* Configuration for our key scanning algorithm */
+struct ec_cros_ec_config {
+ uint32_t valid_mask; /* valid fields */
+ uint8_t flags; /* some flags (enum cros_ec_config_flags) */
+ uint8_t valid_flags; /* which flags are valid */
+ uint16_t scan_period_us; /* period between start of scans */
+ /* revert to interrupt mode after no activity for this long */
+ uint32_t poll_timeout_us;
+ /*
+ * minimum post-scan relax time. Once we finish a scan we check
+ * the time until we are due to start the next one. If this time is
+ * shorter this field, we use this instead.
+ */
+ uint16_t min_post_scan_delay_us;
+ /* delay between setting up output and waiting for it to settle */
+ uint16_t output_settle_us;
+ uint16_t debounce_down_us; /* time for debounce on key down */
+ uint16_t debounce_up_us; /* time for debounce on key up */
+ /* maximum depth to allow for fifo (0 = no keyscan output) */
+ uint8_t fifo_max_depth;
+} __packed;
+
+struct ec_params_cros_ec_set_config {
+ struct ec_cros_ec_config config;
+} __packed;
+
+struct ec_response_cros_ec_get_config {
+ struct ec_cros_ec_config config;
+} __packed;
+
+/* Run the key scan emulation */
+#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66
+
+enum ec_keyscan_seq_cmd {
+ EC_KEYSCAN_SEQ_STATUS = 0, /* Get status information */
+ EC_KEYSCAN_SEQ_CLEAR = 1, /* Clear sequence */
+ EC_KEYSCAN_SEQ_ADD = 2, /* Add item to sequence */
+ EC_KEYSCAN_SEQ_START = 3, /* Start running sequence */
+ EC_KEYSCAN_SEQ_COLLECT = 4, /* Collect sequence summary data */
+};
+
+enum ec_collect_flags {
+ /*
+ * Indicates this scan was processed by the EC. Due to timing, some
+ * scans may be skipped.
+ */
+ EC_KEYSCAN_SEQ_FLAG_DONE = 1 << 0,
+};
+
+struct ec_collect_item {
+ uint8_t flags; /* some flags (enum ec_collect_flags) */
+};
+
+struct ec_params_keyscan_seq_ctrl {
+ uint8_t cmd; /* Command to send (enum ec_keyscan_seq_cmd) */
+ union {
+ struct {
+ uint8_t active; /* still active */
+ uint8_t num_items; /* number of items */
+ /* Current item being presented */
+ uint8_t cur_item;
+ } status;
+ struct {
+ /*
+ * Absolute time for this scan, measured from the
+ * start of the sequence.
+ */
+ uint32_t time_us;
+ uint8_t scan[0]; /* keyscan data */
+ } add;
+ struct {
+ uint8_t start_item; /* First item to return */
+ uint8_t num_items; /* Number of items to return */
+ } collect;
+ };
+} __packed;
+
+struct ec_result_keyscan_seq_ctrl {
+ union {
+ struct {
+ uint8_t num_items; /* Number of items */
+ /* Data for each item */
+ struct ec_collect_item item[0];
+ } collect;
+ };
+} __packed;
+
+/*****************************************************************************/
+/* Temperature sensor commands */
+
+/* Read temperature sensor info */
+#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70
+
+struct ec_params_temp_sensor_get_info {
+ uint8_t id;
+} __packed;
+
+struct ec_response_temp_sensor_get_info {
+ char sensor_name[32];
+ uint8_t sensor_type;
+} __packed;
+
+/*****************************************************************************/
+
+/*
+ * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI
+ * commands accidentally sent to the wrong interface. See the ACPI section
+ * below.
+ */
+
+/*****************************************************************************/
+/* Host event commands */
+
+/*
+ * Host event mask params and response structures, shared by all of the host
+ * event commands below.
+ */
+struct ec_params_host_event_mask {
+ uint32_t mask;
+} __packed;
+
+struct ec_response_host_event_mask {
+ uint32_t mask;
+} __packed;
+
+/* These all use ec_response_host_event_mask */
+#define EC_CMD_HOST_EVENT_GET_B 0x87
+#define EC_CMD_HOST_EVENT_GET_SMI_MASK 0x88
+#define EC_CMD_HOST_EVENT_GET_SCI_MASK 0x89
+#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d
+
+/* These all use ec_params_host_event_mask */
+#define EC_CMD_HOST_EVENT_SET_SMI_MASK 0x8a
+#define EC_CMD_HOST_EVENT_SET_SCI_MASK 0x8b
+#define EC_CMD_HOST_EVENT_CLEAR 0x8c
+#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e
+#define EC_CMD_HOST_EVENT_CLEAR_B 0x8f
+
+/*****************************************************************************/
+/* Switch commands */
+
+/* Enable/disable LCD backlight */
+#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90
+
+struct ec_params_switch_enable_backlight {
+ uint8_t enabled;
+} __packed;
+
+/* Enable/disable WLAN/Bluetooth */
+#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91
+
+struct ec_params_switch_enable_wireless {
+ uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* GPIO commands. Only available on EC if write protect has been disabled. */
+
+/* Set GPIO output value */
+#define EC_CMD_GPIO_SET 0x92
+
+struct ec_params_gpio_set {
+ char name[32];
+ uint8_t val;
+} __packed;
+
+/* Get GPIO value */
+#define EC_CMD_GPIO_GET 0x93
+
+struct ec_params_gpio_get {
+ char name[32];
+} __packed;
+struct ec_response_gpio_get {
+ uint8_t val;
+} __packed;
+
+/*****************************************************************************/
+/* I2C commands. Only available when flash write protect is unlocked. */
+
+/* Read I2C bus */
+#define EC_CMD_I2C_READ 0x94
+
+struct ec_params_i2c_read {
+ uint16_t addr;
+ uint8_t read_size; /* Either 8 or 16. */
+ uint8_t port;
+ uint8_t offset;
+} __packed;
+struct ec_response_i2c_read {
+ uint16_t data;
+} __packed;
+
+/* Write I2C bus */
+#define EC_CMD_I2C_WRITE 0x95
+
+struct ec_params_i2c_write {
+ uint16_t data;
+ uint16_t addr;
+ uint8_t write_size; /* Either 8 or 16. */
+ uint8_t port;
+ uint8_t offset;
+} __packed;
+
+/*****************************************************************************/
+/* Charge state commands. Only available when flash write protect unlocked. */
+
+/* Force charge state machine to stop in idle mode */
+#define EC_CMD_CHARGE_FORCE_IDLE 0x96
+
+struct ec_params_force_idle {
+ uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* Console commands. Only available when flash write protect is unlocked. */
+
+/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */
+#define EC_CMD_CONSOLE_SNAPSHOT 0x97
+
+/*
+ * Read next chunk of data from saved snapshot.
+ *
+ * Response is null-terminated string. Empty string, if there is no more
+ * remaining output.
+ */
+#define EC_CMD_CONSOLE_READ 0x98
+
+/*****************************************************************************/
+
+/*
+ * Cut off battery power output if the battery supports.
+ *
+ * For unsupported battery, just don't implement this command and lets EC
+ * return EC_RES_INVALID_COMMAND.
+ */
+#define EC_CMD_BATTERY_CUT_OFF 0x99
+
+/*****************************************************************************/
+/* USB port mux control. */
+
+/*
+ * Switch USB mux or return to automatic switching.
+ */
+#define EC_CMD_USB_MUX 0x9a
+
+struct ec_params_usb_mux {
+ uint8_t mux;
+} __packed;
+
+/*****************************************************************************/
+/* LDOs / FETs control. */
+
+enum ec_ldo_state {
+ EC_LDO_STATE_OFF = 0, /* the LDO / FET is shut down */
+ EC_LDO_STATE_ON = 1, /* the LDO / FET is ON / providing power */
+};
+
+/*
+ * Switch on/off a LDO.
+ */
+#define EC_CMD_LDO_SET 0x9b
+
+struct ec_params_ldo_set {
+ uint8_t index;
+ uint8_t state;
+} __packed;
+
+/*
+ * Get LDO state.
+ */
+#define EC_CMD_LDO_GET 0x9c
+
+struct ec_params_ldo_get {
+ uint8_t index;
+} __packed;
+
+struct ec_response_ldo_get {
+ uint8_t state;
+} __packed;
+
+/*****************************************************************************/
+/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */
+
+/*
+ * Dump charge state machine context.
+ *
+ * Response is a binary dump of charge state machine context.
+ */
+#define EC_CMD_CHARGE_DUMP 0xa0
+
+/*
+ * Set maximum battery charging current.
+ */
+#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1
+
+struct ec_params_current_limit {
+ uint32_t limit;
+} __packed;
+
+/*****************************************************************************/
+/* Smart battery pass-through */
+
+/* Get / Set 16-bit smart battery registers */
+#define EC_CMD_SB_READ_WORD 0xb0
+#define EC_CMD_SB_WRITE_WORD 0xb1
+
+/* Get / Set string smart battery parameters
+ * formatted as SMBUS "block".
+ */
+#define EC_CMD_SB_READ_BLOCK 0xb2
+#define EC_CMD_SB_WRITE_BLOCK 0xb3
+
+struct ec_params_sb_rd {
+ uint8_t reg;
+} __packed;
+
+struct ec_response_sb_rd_word {
+ uint16_t value;
+} __packed;
+
+struct ec_params_sb_wr_word {
+ uint8_t reg;
+ uint16_t value;
+} __packed;
+
+struct ec_response_sb_rd_block {
+ uint8_t data[32];
+} __packed;
+
+struct ec_params_sb_wr_block {
+ uint8_t reg;
+ uint16_t data[32];
+} __packed;
+
+/*****************************************************************************/
+/* System commands */
+
+/*
+ * TODO: this is a confusing name, since it doesn't necessarily reboot the EC.
+ * Rename to "set image" or something similar.
+ */
+#define EC_CMD_REBOOT_EC 0xd2
+
+/* Command */
+enum ec_reboot_cmd {
+ EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */
+ EC_REBOOT_JUMP_RO = 1, /* Jump to RO without rebooting */
+ EC_REBOOT_JUMP_RW = 2, /* Jump to RW without rebooting */
+ /* (command 3 was jump to RW-B) */
+ EC_REBOOT_COLD = 4, /* Cold-reboot */
+ EC_REBOOT_DISABLE_JUMP = 5, /* Disable jump until next reboot */
+ EC_REBOOT_HIBERNATE = 6 /* Hibernate EC */
+};
+
+/* Flags for ec_params_reboot_ec.reboot_flags */
+#define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */
+#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1) /* Reboot after AP shutdown */
+
+struct ec_params_reboot_ec {
+ uint8_t cmd; /* enum ec_reboot_cmd */
+ uint8_t flags; /* See EC_REBOOT_FLAG_* */
+} __packed;
+
+/*
+ * Get information on last EC panic.
+ *
+ * Returns variable-length platform-dependent panic information. See panic.h
+ * for details.
+ */
+#define EC_CMD_GET_PANIC_INFO 0xd3
+
+/*****************************************************************************/
+/*
+ * ACPI commands
+ *
+ * These are valid ONLY on the ACPI command/data port.
+ */
+
+/*
+ * ACPI Read Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ * - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD
+ * - Wait for EC_LPC_CMDR_PENDING bit to clear
+ * - Write address to EC_LPC_ADDR_ACPI_DATA
+ * - Wait for EC_LPC_CMDR_DATA bit to set
+ * - Read value from EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_READ 0x80
+
+/*
+ * ACPI Write Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ * - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD
+ * - Wait for EC_LPC_CMDR_PENDING bit to clear
+ * - Write address to EC_LPC_ADDR_ACPI_DATA
+ * - Wait for EC_LPC_CMDR_PENDING bit to clear
+ * - Write value to EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_WRITE 0x81
+
+/*
+ * ACPI Query Embedded Controller
+ *
+ * This clears the lowest-order bit in the currently pending host events, and
+ * sets the result code to the 1-based index of the bit (event 0x00000001 = 1,
+ * event 0x80000000 = 32), or 0 if no event was pending.
+ */
+#define EC_CMD_ACPI_QUERY_EVENT 0x84
+
+/* Valid addresses in ACPI memory space, for read/write commands */
+/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */
+#define EC_ACPI_MEM_VERSION 0x00
+/*
+ * Test location; writing value here updates test compliment byte to (0xff -
+ * value).
+ */
+#define EC_ACPI_MEM_TEST 0x01
+/* Test compliment; writes here are ignored. */
+#define EC_ACPI_MEM_TEST_COMPLIMENT 0x02
+/* Keyboard backlight brightness percent (0 - 100) */
+#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03
+
+/* Current version of ACPI memory address space */
+#define EC_ACPI_MEM_VERSION_CURRENT 1
+
+
+/*****************************************************************************/
+/*
+ * Special commands
+ *
+ * These do not follow the normal rules for commands. See each command for
+ * details.
+ */
+
+/*
+ * Reboot NOW
+ *
+ * This command will work even when the EC LPC interface is busy, because the
+ * reboot command is processed at interrupt level. Note that when the EC
+ * reboots, the host will reboot too, so there is no response to this command.
+ *
+ * Use EC_CMD_REBOOT_EC to reboot the EC more politely.
+ */
+#define EC_CMD_REBOOT 0xd1 /* Think "die" */
+
+/*
+ * Resend last response (not supported on LPC).
+ *
+ * Returns EC_RES_UNAVAILABLE if there is no response available - for example,
+ * there was no previous command, or the previous command's response was too
+ * big to save.
+ */
+#define EC_CMD_RESEND_RESPONSE 0xdb
+
+/*
+ * This header byte on a command indicate version 0. Any header byte less
+ * than this means that we are talking to an old EC which doesn't support
+ * versioning. In that case, we assume version 0.
+ *
+ * Header bytes greater than this indicate a later version. For example,
+ * EC_CMD_VERSION0 + 1 means we are using version 1.
+ *
+ * The old EC interface must not use commands 0dc or higher.
+ */
+#define EC_CMD_VERSION0 0xdc
+
+#endif /* !__ACPI__ */
+
+#endif /* __CROS_EC_COMMANDS_H */
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 8845e29..d93e102 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -84,6 +84,8 @@ enum fdt_compat_id {
COMPAT_SAMSUNG_EXYNOS5_SOUND, /* Exynos Sound */
COMPAT_WOLFSON_WM8994_CODEC, /* Wolfson WM8994 Sound Codec */
COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */
+ COMPAT_GOOGLE_CROS_EC, /* Google CROS_EC Protocol */
+ COMPAT_GOOGLE_CROS_EC_KEYB, /* Google CROS_EC Keyboard */
COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
diff --git a/include/ide.h b/include/ide.h
index afea85c..f691a74 100644
--- a/include/ide.h
+++ b/include/ide.h
@@ -54,8 +54,9 @@ typedef ulong lbaint_t;
*/
void ide_init(void);
-ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer);
-ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer);
+ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer);
+ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt,
+ const void *buffer);
#ifdef CONFIG_IDE_PREINIT
int ide_preinit(void);
diff --git a/include/image.h b/include/image.h
index 8ccc00b..2614918 100644
--- a/include/image.h
+++ b/include/image.h
@@ -46,6 +46,9 @@ struct lmb;
#define CONFIG_OF_LIBFDT 1
#define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */
+/* Support FIT image signing on host */
+#define CONFIG_FIT_SIGNATURE
+
#define IMAGE_ENABLE_IGNORE 0
#define IMAGE_INDENT_STRING ""
@@ -320,13 +323,16 @@ typedef struct bootm_headers {
int verify; /* getenv("verify")[0] != 'n' */
#define BOOTM_STATE_START (0x00000001)
-#define BOOTM_STATE_LOADOS (0x00000002)
-#define BOOTM_STATE_RAMDISK (0x00000004)
-#define BOOTM_STATE_FDT (0x00000008)
-#define BOOTM_STATE_OS_CMDLINE (0x00000010)
-#define BOOTM_STATE_OS_BD_T (0x00000020)
-#define BOOTM_STATE_OS_PREP (0x00000040)
-#define BOOTM_STATE_OS_GO (0x00000080)
+#define BOOTM_STATE_FINDOS (0x00000002)
+#define BOOTM_STATE_FINDOTHER (0x00000004)
+#define BOOTM_STATE_LOADOS (0x00000008)
+#define BOOTM_STATE_RAMDISK (0x00000010)
+#define BOOTM_STATE_FDT (0x00000020)
+#define BOOTM_STATE_OS_CMDLINE (0x00000040)
+#define BOOTM_STATE_OS_BD_T (0x00000080)
+#define BOOTM_STATE_OS_PREP (0x00000100)
+#define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* 'Almost' run the OS */
+#define BOOTM_STATE_OS_GO (0x00000400)
int state;
#ifdef CONFIG_LMB
@@ -667,11 +673,12 @@ int image_setup_linux(bootm_headers_t *images);
#define FIT_IMAGES_PATH "/images"
#define FIT_CONFS_PATH "/configurations"
-/* hash node */
+/* hash/signature node */
#define FIT_HASH_NODENAME "hash"
#define FIT_ALGO_PROP "algo"
#define FIT_VALUE_PROP "value"
#define FIT_IGNORE_PROP "uboot-ignore"
+#define FIT_SIG_NODENAME "signature"
/* image node */
#define FIT_DATA_PROP "data"
@@ -759,12 +766,26 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
int fit_set_timestamp(void *fit, int noffset, time_t timestamp);
/**
- * fit_add_verification_data() - Calculate and add hashes to FIT
+ * fit_add_verification_data() - add verification data to FIT image nodes
+ *
+ * @keydir: Directory containing keys
+ * @kwydest: FDT blob to write public key information to
+ * @fit: Pointer to the FIT format image header
+ * @comment: Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ *
+ * Adds hash values for all component images in the FIT blob.
+ * Hashes are calculated for all component images which have hash subnodes
+ * with algorithm property set to one of the supported hash algorithms.
+ *
+ * Also add signatures if signature nodes are present.
*
- * @fit: Fit image to process
- * @return 0 if ok, <0 for error
+ * returns
+ * 0, on success
+ * libfdt error code, on failure
*/
-int fit_add_verification_data(void *fit);
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+ const char *comment, int require_keys);
int fit_image_verify(const void *fit, int noffset);
int fit_config_verify(const void *fit, int conf_noffset);
@@ -801,15 +822,19 @@ int calculate_hash(const void *data, int data_len, const char *algo,
uint8_t *value, int *value_len);
/*
- * At present we only support verification on the device
+ * At present we only support signing on the host, and verification on the
+ * device
*/
#if defined(CONFIG_FIT_SIGNATURE)
# ifdef USE_HOSTCC
+# define IMAGE_ENABLE_SIGN 1
# define IMAGE_ENABLE_VERIFY 0
#else
+# define IMAGE_ENABLE_SIGN 0
# define IMAGE_ENABLE_VERIFY 1
# endif
#else
+# define IMAGE_ENABLE_SIGN 0
# define IMAGE_ENABLE_VERIFY 0
#endif
@@ -825,6 +850,137 @@ int calculate_hash(const void *data, int data_len, const char *algo,
#define IMAGE_ENABLE_BEST_MATCH 0
#endif
+/* Information passed to the signing routines */
+struct image_sign_info {
+ const char *keydir; /* Directory conaining keys */
+ const char *keyname; /* Name of key to use */
+ void *fit; /* Pointer to FIT blob */
+ int node_offset; /* Offset of signature node */
+ struct image_sig_algo *algo; /* Algorithm information */
+ const void *fdt_blob; /* FDT containing public keys */
+ int required_keynode; /* Node offset of key to use: -1=any */
+ const char *require_keys; /* Value for 'required' property */
+};
+
+/* A part of an image, used for hashing */
+struct image_region {
+ const void *data;
+ int size;
+};
+
+struct image_sig_algo {
+ const char *name; /* Name of algorithm */
+
+ /**
+ * sign() - calculate and return signature for given input data
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sigp: Set to an allocated buffer holding the signature
+ * @sig_len: Set to length of the calculated hash
+ *
+ * This computes input data signature according to selected algorithm.
+ * Resulting signature value is placed in an allocated buffer, the
+ * pointer is returned as *sigp. The length of the calculated
+ * signature is returned via the sig_len pointer argument. The caller
+ * should free *sigp.
+ *
+ * @return: 0, on success, -ve on error
+ */
+ int (*sign)(struct image_sign_info *info,
+ const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_len);
+
+ /**
+ * add_verify_data() - Add verification information to FDT
+ *
+ * Add public key information to the FDT node, suitable for
+ * verification at run-time. The information added depends on the
+ * algorithm being used.
+ *
+ * @info: Specifies key and FIT information
+ * @keydest: Destination FDT blob for public key data
+ * @return: 0, on success, -ve on error
+ */
+ int (*add_verify_data)(struct image_sign_info *info, void *keydest);
+
+ /**
+ * verify() - Verify a signature against some data
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sig: Signature
+ * @sig_len: Number of bytes in signature
+ * @return 0 if verified, -ve on error
+ */
+ int (*verify)(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len);
+};
+
+/**
+ * image_get_sig_algo() - Look up a signature algortihm
+ *
+ * @param name Name of algorithm
+ * @return pointer to algorithm information, or NULL if not found
+ */
+struct image_sig_algo *image_get_sig_algo(const char *name);
+
+/**
+ * fit_image_verify_required_sigs() - Verify signatures marked as 'required'
+ *
+ * @fit: FIT to check
+ * @image_noffset: Offset of image node to check
+ * @data: Image data to check
+ * @size: Size of image data
+ * @sig_blob: FDT containing public keys
+ * @no_sigsp: Returns 1 if no signatures were required, and
+ * therefore nothing was checked. The caller may wish
+ * to fall back to other mechanisms, or refuse to
+ * boot.
+ * @return 0 if all verified ok, <0 on error
+ */
+int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+ const char *data, size_t size, const void *sig_blob,
+ int *no_sigsp);
+
+/**
+ * fit_image_check_sig() - Check a single image signature node
+ *
+ * @fit: FIT to check
+ * @noffset: Offset of signature node to check
+ * @data: Image data to check
+ * @size: Size of image data
+ * @required_keynode: Offset in the control FDT of the required key node,
+ * if any. If this is given, then the image wil not
+ * pass verification unless that key is used. If this is
+ * -1 then any signature will do.
+ * @err_msgp: In the event of an error, this will be pointed to a
+ * help error string to display to the user.
+ * @return 0 if all verified ok, <0 on error
+ */
+int fit_image_check_sig(const void *fit, int noffset, const void *data,
+ size_t size, int required_keynode, char **err_msgp);
+
+/**
+ * fit_region_make_list() - Make a list of regions to hash
+ *
+ * Given a list of FIT regions (offset, size) provided by libfdt, create
+ * a list of regions (void *, size) for use by the signature creationg
+ * and verification code.
+ *
+ * @fit: FIT image to process
+ * @fdt_regions: Regions as returned by libfdt
+ * @count: Number of regions returned by libfdt
+ * @region: Place to put list of regions (NULL to allocate it)
+ * @return pointer to list of regions, or NULL if out of memory
+ */
+struct image_region *fit_region_make_list(const void *fit,
+ struct fdt_region *fdt_regions, int count,
+ struct image_region *region);
+
static inline int fit_image_check_target_arch(const void *fdt, int node)
{
return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT);
diff --git a/include/libfdt.h b/include/libfdt.h
index c5ec2ac..765d84f 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -1511,4 +1511,68 @@ int fdt_del_node(void *fdt, int nodeoffset);
const char *fdt_strerror(int errval);
+struct fdt_region {
+ int offset;
+ int size;
+};
+
+/**
+ * fdt_find_regions() - find regions in device tree
+ *
+ * Given a list of nodes to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ *
+ * Nodes which are given in 'inc' are included in the region list, as
+ * are the names of the immediate subnodes nodes (but not the properties
+ * or subnodes of those subnodes).
+ *
+ * For eaxample "/" means to include the root node, all root properties
+ * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter
+ * ensures that we capture the names of the subnodes. In a hashing situation
+ * it prevents the root node from changing at all Any change to non-excluded
+ * properties, names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too.
+ *
+ * The device tree header is not included in the list.
+ *
+ * @fdt: Device tree to check
+ * @inc: List of node paths to included
+ * @inc_count: Number of node paths in list
+ * @exc_prop: List of properties names to exclude
+ * @exc_prop_count: Number of properties in exclude list
+ * @region: Returns list of regions
+ * @max_region: Maximum length of region list
+ * @path: Pointer to a temporary string for the function to use for
+ * building path names
+ * @path_len: Length of path, must be large enough to hold the longest
+ * path in the tree
+ * @add_string_tab: 1 to add a region for the string table
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again.
+ */
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+ char * const exc_prop[], int exc_prop_count,
+ struct fdt_region region[], int max_regions,
+ char *path, int path_len, int add_string_tab);
+
#endif /* _LIBFDT_H */
diff --git a/include/part.h b/include/part.h
index f7c7cc5..35c1c5b 100644
--- a/include/part.h
+++ b/include/part.h
@@ -43,15 +43,15 @@ typedef struct block_dev_desc {
char product[20+1]; /* IDE Serial no, SCSI product */
char revision[8+1]; /* firmware revision */
unsigned long (*block_read)(int dev,
- unsigned long start,
+ lbaint_t start,
lbaint_t blkcnt,
void *buffer);
unsigned long (*block_write)(int dev,
- unsigned long start,
+ lbaint_t start,
lbaint_t blkcnt,
const void *buffer);
unsigned long (*block_erase)(int dev,
- unsigned long start,
+ lbaint_t start,
lbaint_t blkcnt);
void *priv; /* driver private struct pointer */
}block_dev_desc_t;
diff --git a/include/pci.h b/include/pci.h
index f9c5148..98ba151 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -462,7 +462,7 @@ struct pci_region {
#define PCI_REGION_SYS_MEMORY 0x00000100 /* System memory */
#define PCI_REGION_RO 0x00000200 /* Read-only memory */
-extern __inline__ void pci_set_region(struct pci_region *reg,
+static inline void pci_set_region(struct pci_region *reg,
pci_addr_t bus_start,
phys_addr_t phys_start,
pci_size_t size,
@@ -548,7 +548,7 @@ struct pci_controller {
void *priv_data;
};
-extern __inline__ void pci_set_ops(struct pci_controller *hose,
+static inline void pci_set_ops(struct pci_controller *hose,
int (*read_byte)(struct pci_controller*,
pci_dev_t, int where, u8 *),
int (*read_word)(struct pci_controller*,
diff --git a/include/rsa.h b/include/rsa.h
new file mode 100644
index 0000000..a5dd676
--- /dev/null
+++ b/include/rsa.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _RSA_H
+#define _RSA_H
+
+#include <errno.h>
+#include <image.h>
+
+#if IMAGE_ENABLE_SIGN
+/**
+ * sign() - calculate and return signature for given input data
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sigp: Set to an allocated buffer holding the signature
+ * @sig_len: Set to length of the calculated hash
+ *
+ * This computes input data signature according to selected algorithm.
+ * Resulting signature value is placed in an allocated buffer, the
+ * pointer is returned as *sigp. The length of the calculated
+ * signature is returned via the sig_len pointer argument. The caller
+ * should free *sigp.
+ *
+ * @return: 0, on success, -ve on error
+ */
+int rsa_sign(struct image_sign_info *info,
+ const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_len);
+
+/**
+ * add_verify_data() - Add verification information to FDT
+ *
+ * Add public key information to the FDT node, suitable for
+ * verification at run-time. The information added depends on the
+ * algorithm being used.
+ *
+ * @info: Specifies key and FIT information
+ * @keydest: Destination FDT blob for public key data
+ * @return: 0, on success, -ve on error
+*/
+int rsa_add_verify_data(struct image_sign_info *info, void *keydest);
+#else
+static inline int rsa_sign(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t **sigp, uint *sig_len)
+{
+ return -ENXIO;
+}
+
+static inline int rsa_add_verify_data(struct image_sign_info *info,
+ void *keydest)
+{
+ return -ENXIO;
+}
+#endif
+
+#if IMAGE_ENABLE_VERIFY
+/**
+ * rsa_verify() - Verify a signature against some data
+ *
+ * Verify a RSA PKCS1.5 signature against an expected hash.
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sig: Signature
+ * @sig_len: Number of bytes in signature
+ * @return 0 if verified, -ve on error
+ */
+int rsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len);
+#else
+static inline int rsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len)
+{
+ return -ENXIO;
+}
+#endif
+
+#endif
diff --git a/include/spi.h b/include/spi.h
index 1638b50..e8e6544 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -247,4 +247,20 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte)
return ret < 0 ? ret : din[1];
}
+/**
+ * Set up a SPI slave for a particular device tree node
+ *
+ * This calls spi_setup_slave() with the correct bus number. Call
+ * spi_free_slave() to free it later.
+ *
+ * @param blob Device tree blob
+ * @param node SPI peripheral node to use
+ * @param cs Chip select to use
+ * @param max_hz Maximum SCK rate in Hz (0 for default)
+ * @param mode Clock polarity, clock phase and other parameters
+ * @return pointer to new spi_slave structure
+ */
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
+ unsigned int cs, unsigned int max_hz, unsigned int mode);
+
#endif /* _SPI_H_ */
diff --git a/include/trace.h b/include/trace.h
new file mode 100644
index 0000000..8082466
--- /dev/null
+++ b/include/trace.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __TRACE_H
+#define __TRACE_H
+
+enum {
+ /*
+ * This affects the granularity of our trace. We can bin function
+ * entry points into groups on the basis that functions typically
+ * have a minimum size, so entry points can't appear any closer
+ * than this to each other.
+ *
+ * The value here assumes a minimum instruction size of 4 bytes,
+ * or that instructions are 2 bytes but there are at least 2 of
+ * them in every function.
+ *
+ * Increasing this value reduces the number of functions we can
+ * resolve, but reduces the size of the uintptr_t array used for
+ * our function list, which is the length of the code divided by
+ * this value.
+ */
+ FUNC_SITE_SIZE = 4, /* distance between function sites */
+};
+
+enum trace_chunk_type {
+ TRACE_CHUNK_FUNCS,
+ TRACE_CHUNK_CALLS,
+};
+
+/* A trace record for a function, as written to the profile output file */
+struct trace_output_func {
+ uint32_t offset; /* Function offset into code */
+ uint32_t call_count; /* Number of times called */
+};
+
+/* A header at the start of the trace output buffer */
+struct trace_output_hdr {
+ enum trace_chunk_type type; /* Record type */
+ uint32_t rec_count; /* Number of records */
+};
+
+/* Print statistics about traced function calls */
+void trace_print_stats(void);
+
+/**
+ * Dump a list of functions and call counts into a buffer
+ *
+ * Each record in the buffer is a struct trace_func_stats. The 'needed'
+ * parameter returns the number of bytes needed to complete the operation,
+ * which may be more than buff_size if your buffer is too small.
+ *
+ * @param buff Buffer in which to place data, or NULL to count size
+ * @param buff_size Size of buffer
+ * @param needed Returns number of bytes used / needed
+ * @return 0 if ok, -1 on error (buffer exhausted)
+ */
+int trace_list_functions(void *buff, int buff_size, unsigned *needed);
+
+/* Flags for ftrace_record */
+enum ftrace_flags {
+ FUNCF_EXIT = 0UL << 30,
+ FUNCF_ENTRY = 1UL << 30,
+ FUNCF_TEXTBASE = 2UL << 30,
+
+ FUNCF_TIMESTAMP_MASK = 0x3fffffff,
+};
+
+#define TRACE_CALL_TYPE(call) ((call)->flags & 0xc0000000UL)
+
+/* Information about a single function entry/exit */
+struct trace_call {
+ uint32_t func; /* Function offset */
+ uint32_t caller; /* Caller function offset */
+ uint32_t flags; /* Flags and timestamp */
+};
+
+int trace_list_calls(void *buff, int buff_size, unsigned int *needed);
+
+/**
+ * Turn function tracing on and off
+ *
+ * Don't enable trace if it has not been initialised.
+ *
+ * @param enabled 1 to enable trace, 0 to disable
+ */
+void trace_set_enabled(int enabled);
+
+#ifdef CONFIG_TRACE_EARLY
+int trace_early_init(void);
+#else
+static inline int trace_early_init(void)
+{
+ return 0;
+}
+#endif
+
+/**
+ * Init the trace system
+ *
+ * This should be called after relocation with a suitably large buffer
+ * (typically as large as the U-Boot text area)
+ *
+ * @param buff Pointer to trace buffer
+ * @param buff_size Size of trace buffer
+ */
+int trace_init(void *buff, size_t buff_size);
+
+#endif
diff --git a/include/vsprintf.h b/include/vsprintf.h
index 651077c..6568854 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -178,4 +178,15 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
#define vscnprintf(buf, size, fmt, args...) vsprintf(buf, fmt, ##args)
#endif /* CONFIG_SYS_VSNPRINTF */
+/**
+ * print_grouped_ull() - print a value with digits grouped by ','
+ *
+ * This prints a value with grouped digits, like 12,345,678 to make it easier
+ * to read.
+ *
+ * @val: Value to print
+ * @digits: Number of digiits to print
+ */
+void print_grouped_ull(unsigned long long int_val, int digits);
+
#endif
diff --git a/lib/Makefile b/lib/Makefile
index a94830f..f5a8819 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,6 +71,7 @@ COBJS-y += linux_string.o
COBJS-$(CONFIG_REGEX) += slre.o
COBJS-y += string.o
COBJS-y += time.o
+COBJS-$(CONFIG_TRACE) += trace.o
COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
COBJS-y += vsprintf.o
COBJS-$(CONFIG_RANDOM_MACADDR) += rand.o
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index ad25a0c..b314268 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -57,6 +57,8 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
+ COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
+ COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c
index 63e67b7..b9e3c4a 100644
--- a/lib/libfdt/fdt_wip.c
+++ b/lib/libfdt/fdt_wip.c
@@ -120,3 +120,132 @@ int fdt_nop_node(void *fdt, int nodeoffset)
endoffset - nodeoffset);
return 0;
}
+
+#define FDT_MAX_DEPTH 32
+
+static int str_in_list(const char *str, char * const list[], int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ if (!strcmp(list[i], str))
+ return 1;
+
+ return 0;
+}
+
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+ char * const exc_prop[], int exc_prop_count,
+ struct fdt_region region[], int max_regions,
+ char *path, int path_len, int add_string_tab)
+{
+ int stack[FDT_MAX_DEPTH];
+ char *end;
+ int nextoffset = 0;
+ uint32_t tag;
+ int count = 0;
+ int start = -1;
+ int depth = -1;
+ int want = 0;
+ int base = fdt_off_dt_struct(fdt);
+
+ end = path;
+ *end = '\0';
+ do {
+ const struct fdt_property *prop;
+ const char *name;
+ const char *str;
+ int include = 0;
+ int stop_at = 0;
+ int offset;
+ int len;
+
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ stop_at = nextoffset;
+
+ switch (tag) {
+ case FDT_PROP:
+ include = want >= 2;
+ stop_at = offset;
+ prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (str_in_list(str, exc_prop, exc_prop_count))
+ include = 0;
+ break;
+
+ case FDT_NOP:
+ include = want >= 2;
+ stop_at = offset;
+ break;
+
+ case FDT_BEGIN_NODE:
+ depth++;
+ if (depth == FDT_MAX_DEPTH)
+ return -FDT_ERR_BADSTRUCTURE;
+ name = fdt_get_name(fdt, offset, &len);
+ if (end - path + 2 + len >= path_len)
+ return -FDT_ERR_NOSPACE;
+ if (end != path + 1)
+ *end++ = '/';
+ strcpy(end, name);
+ end += len;
+ stack[depth] = want;
+ if (want == 1)
+ stop_at = offset;
+ if (str_in_list(path, inc, inc_count))
+ want = 2;
+ else if (want)
+ want--;
+ else
+ stop_at = offset;
+ include = want;
+ break;
+
+ case FDT_END_NODE:
+ include = want;
+ want = stack[depth--];
+ while (end > path && *--end != '/')
+ ;
+ *end = '\0';
+ break;
+
+ case FDT_END:
+ include = 1;
+ break;
+ }
+
+ if (include && start == -1) {
+ /* Should we merge with previous? */
+ if (count && count <= max_regions &&
+ offset == region[count - 1].offset +
+ region[count - 1].size - base)
+ start = region[--count].offset - base;
+ else
+ start = offset;
+ }
+
+ if (!include && start != -1) {
+ if (count < max_regions) {
+ region[count].offset = base + start;
+ region[count].size = stop_at - start;
+ }
+ count++;
+ start = -1;
+ }
+ } while (tag != FDT_END);
+
+ if (nextoffset != fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADLAYOUT;
+
+ /* Add a region for the END tag and the string table */
+ if (count < max_regions) {
+ region[count].offset = base + start;
+ region[count].size = nextoffset - start;
+ if (add_string_tab)
+ region[count].size += fdt_size_dt_strings(fdt);
+ }
+ count++;
+
+ return count;
+}
diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
new file mode 100644
index 0000000..9eb3e40
--- /dev/null
+++ b/lib/rsa/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2013, Google Inc.
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)librsa.o
+
+ifdef CONFIG_FIT_SIGNATURE
+COBJS-$(CONFIG_RSA) += rsa-verify.o
+endif
+
+COBJS := $(sort $(COBJS-y))
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
new file mode 100644
index 0000000..a75ae24
--- /dev/null
+++ b/lib/rsa/rsa-sign.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include <image.h>
+#include <time.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define HAVE_ERR_REMOVE_THREAD_STATE
+#endif
+
+static int rsa_err(const char *msg)
+{
+ unsigned long sslErr = ERR_get_error();
+
+ fprintf(stderr, "%s", msg);
+ fprintf(stderr, ": %s\n",
+ ERR_error_string(sslErr, 0));
+
+ return -1;
+}
+
+/**
+ * rsa_get_pub_key() - read a public key from a .crt file
+ *
+ * @keydir: Directory containins the key
+ * @name Name of key file (will have a .crt extension)
+ * @rsap Returns RSA object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ */
+static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap)
+{
+ char path[1024];
+ EVP_PKEY *key;
+ X509 *cert;
+ RSA *rsa;
+ FILE *f;
+ int ret;
+
+ *rsap = NULL;
+ snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
+ f = fopen(path, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
+ path, strerror(errno));
+ return -EACCES;
+ }
+
+ /* Read the certificate */
+ cert = NULL;
+ if (!PEM_read_X509(f, &cert, NULL, NULL)) {
+ rsa_err("Couldn't read certificate");
+ ret = -EINVAL;
+ goto err_cert;
+ }
+
+ /* Get the public key from the certificate. */
+ key = X509_get_pubkey(cert);
+ if (!key) {
+ rsa_err("Couldn't read public key\n");
+ ret = -EINVAL;
+ goto err_pubkey;
+ }
+
+ /* Convert to a RSA_style key. */
+ rsa = EVP_PKEY_get1_RSA(key);
+ if (!rsa) {
+ rsa_err("Couldn't convert to a RSA style key");
+ goto err_rsa;
+ }
+ fclose(f);
+ EVP_PKEY_free(key);
+ X509_free(cert);
+ *rsap = rsa;
+
+ return 0;
+
+err_rsa:
+ EVP_PKEY_free(key);
+err_pubkey:
+ X509_free(cert);
+err_cert:
+ fclose(f);
+ return ret;
+}
+
+/**
+ * rsa_get_priv_key() - read a private key from a .key file
+ *
+ * @keydir: Directory containins the key
+ * @name Name of key file (will have a .key extension)
+ * @rsap Returns RSA object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ */
+static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap)
+{
+ char path[1024];
+ RSA *rsa;
+ FILE *f;
+
+ *rsap = NULL;
+ snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
+ f = fopen(path, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
+ path, strerror(errno));
+ return -ENOENT;
+ }
+
+ rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path);
+ if (!rsa) {
+ rsa_err("Failure reading private key");
+ fclose(f);
+ return -EPROTO;
+ }
+ fclose(f);
+ *rsap = rsa;
+
+ return 0;
+}
+
+static int rsa_init(void)
+{
+ int ret;
+
+ ret = SSL_library_init();
+ if (!ret) {
+ fprintf(stderr, "Failure to init SSL library\n");
+ return -1;
+ }
+ SSL_load_error_strings();
+
+ OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_digests();
+ OpenSSL_add_all_ciphers();
+
+ return 0;
+}
+
+static void rsa_remove(void)
+{
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+ ERR_remove_thread_state(NULL);
+#else
+ ERR_remove_state(0);
+#endif
+ EVP_cleanup();
+}
+
+static int rsa_sign_with_key(RSA *rsa, const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_size)
+{
+ EVP_PKEY *key;
+ EVP_MD_CTX *context;
+ int size, ret = 0;
+ uint8_t *sig;
+ int i;
+
+ key = EVP_PKEY_new();
+ if (!key)
+ return rsa_err("EVP_PKEY object creation failed");
+
+ if (!EVP_PKEY_set1_RSA(key, rsa)) {
+ ret = rsa_err("EVP key setup failed");
+ goto err_set;
+ }
+
+ size = EVP_PKEY_size(key);
+ sig = malloc(size);
+ if (!sig) {
+ fprintf(stderr, "Out of memory for signature (%d bytes)\n",
+ size);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ context = EVP_MD_CTX_create();
+ if (!context) {
+ ret = rsa_err("EVP context creation failed");
+ goto err_create;
+ }
+ EVP_MD_CTX_init(context);
+ if (!EVP_SignInit(context, EVP_sha1())) {
+ ret = rsa_err("Signer setup failed");
+ goto err_sign;
+ }
+
+ for (i = 0; i < region_count; i++) {
+ if (!EVP_SignUpdate(context, region[i].data, region[i].size)) {
+ ret = rsa_err("Signing data failed");
+ goto err_sign;
+ }
+ }
+
+ if (!EVP_SignFinal(context, sig, sig_size, key)) {
+ ret = rsa_err("Could not obtain signature");
+ goto err_sign;
+ }
+ EVP_MD_CTX_cleanup(context);
+ EVP_MD_CTX_destroy(context);
+ EVP_PKEY_free(key);
+
+ debug("Got signature: %d bytes, expected %d\n", *sig_size, size);
+ *sigp = sig;
+ *sig_size = size;
+
+ return 0;
+
+err_sign:
+ EVP_MD_CTX_destroy(context);
+err_create:
+ free(sig);
+err_alloc:
+err_set:
+ EVP_PKEY_free(key);
+ return ret;
+}
+
+int rsa_sign(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t **sigp, uint *sig_len)
+{
+ RSA *rsa;
+ int ret;
+
+ ret = rsa_init();
+ if (ret)
+ return ret;
+
+ ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa);
+ if (ret)
+ goto err_priv;
+ ret = rsa_sign_with_key(rsa, region, region_count, sigp, sig_len);
+ if (ret)
+ goto err_sign;
+
+ RSA_free(rsa);
+ rsa_remove();
+
+ return ret;
+
+err_sign:
+ RSA_free(rsa);
+err_priv:
+ rsa_remove();
+ return ret;
+}
+
+/*
+ * rsa_get_params(): - Get the important parameters of an RSA public key
+ */
+int rsa_get_params(RSA *key, uint32_t *n0_invp, BIGNUM **modulusp,
+ BIGNUM **r_squaredp)
+{
+ BIGNUM *big1, *big2, *big32, *big2_32;
+ BIGNUM *n, *r, *r_squared, *tmp;
+ BN_CTX *bn_ctx = BN_CTX_new();
+ int ret = 0;
+
+ /* Initialize BIGNUMs */
+ big1 = BN_new();
+ big2 = BN_new();
+ big32 = BN_new();
+ r = BN_new();
+ r_squared = BN_new();
+ tmp = BN_new();
+ big2_32 = BN_new();
+ n = BN_new();
+ if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 ||
+ !n) {
+ fprintf(stderr, "Out of memory (bignum)\n");
+ return -ENOMEM;
+ }
+
+ if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) ||
+ !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L))
+ ret = -1;
+
+ /* big2_32 = 2^32 */
+ if (!BN_exp(big2_32, big2, big32, bn_ctx))
+ ret = -1;
+
+ /* Calculate n0_inv = -1 / n[0] mod 2^32 */
+ if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
+ !BN_sub(tmp, big2_32, tmp))
+ ret = -1;
+ *n0_invp = BN_get_word(tmp);
+
+ /* Calculate R = 2^(# of key bits) */
+ if (!BN_set_word(tmp, BN_num_bits(n)) ||
+ !BN_exp(r, big2, tmp, bn_ctx))
+ ret = -1;
+
+ /* Calculate r_squared = R^2 mod n */
+ if (!BN_copy(r_squared, r) ||
+ !BN_mul(tmp, r_squared, r, bn_ctx) ||
+ !BN_mod(r_squared, tmp, n, bn_ctx))
+ ret = -1;
+
+ *modulusp = n;
+ *r_squaredp = r_squared;
+
+ BN_free(big1);
+ BN_free(big2);
+ BN_free(big32);
+ BN_free(r);
+ BN_free(tmp);
+ BN_free(big2_32);
+ if (ret) {
+ fprintf(stderr, "Bignum operations failed\n");
+ return -ENOMEM;
+ }
+
+ return ret;
+}
+
+static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
+ BIGNUM *num, int num_bits)
+{
+ int nwords = num_bits / 32;
+ int size;
+ uint32_t *buf, *ptr;
+ BIGNUM *tmp, *big2, *big32, *big2_32;
+ BN_CTX *ctx;
+ int ret;
+
+ tmp = BN_new();
+ big2 = BN_new();
+ big32 = BN_new();
+ big2_32 = BN_new();
+ if (!tmp || !big2 || !big32 || !big2_32) {
+ fprintf(stderr, "Out of memory (bignum)\n");
+ return -ENOMEM;
+ }
+ ctx = BN_CTX_new();
+ if (!tmp) {
+ fprintf(stderr, "Out of memory (bignum context)\n");
+ return -ENOMEM;
+ }
+ BN_set_word(big2, 2L);
+ BN_set_word(big32, 32L);
+ BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
+
+ size = nwords * sizeof(uint32_t);
+ buf = malloc(size);
+ if (!buf) {
+ fprintf(stderr, "Out of memory (%d bytes)\n", size);
+ return -ENOMEM;
+ }
+
+ /* Write out modulus as big endian array of integers */
+ for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
+ BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
+ *ptr = cpu_to_fdt32(BN_get_word(tmp));
+ BN_rshift(num, num, 32); /* N = N/B */
+ }
+
+ ret = fdt_setprop(blob, noffset, prop_name, buf, size);
+ if (ret) {
+ fprintf(stderr, "Failed to write public key to FIT\n");
+ return -ENOSPC;
+ }
+ free(buf);
+ BN_free(tmp);
+ BN_free(big2);
+ BN_free(big32);
+ BN_free(big2_32);
+
+ return ret;
+}
+
+int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
+{
+ BIGNUM *modulus, *r_squared;
+ uint32_t n0_inv;
+ int parent, node;
+ char name[100];
+ int ret;
+ int bits;
+ RSA *rsa;
+
+ debug("%s: Getting verification data\n", __func__);
+ ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa);
+ if (ret)
+ return ret;
+ ret = rsa_get_params(rsa, &n0_inv, &modulus, &r_squared);
+ if (ret)
+ return ret;
+ bits = BN_num_bits(modulus);
+ parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
+ if (parent == -FDT_ERR_NOTFOUND) {
+ parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME);
+ if (parent < 0) {
+ fprintf(stderr, "Couldn't create signature node: %s\n",
+ fdt_strerror(parent));
+ return -EINVAL;
+ }
+ }
+
+ /* Either create or overwrite the named key node */
+ snprintf(name, sizeof(name), "key-%s", info->keyname);
+ node = fdt_subnode_offset(keydest, parent, name);
+ if (node == -FDT_ERR_NOTFOUND) {
+ node = fdt_add_subnode(keydest, parent, name);
+ if (node < 0) {
+ fprintf(stderr, "Could not create key subnode: %s\n",
+ fdt_strerror(node));
+ return -EINVAL;
+ }
+ } else if (node < 0) {
+ fprintf(stderr, "Cannot select keys parent: %s\n",
+ fdt_strerror(node));
+ return -ENOSPC;
+ }
+
+ ret = fdt_setprop_string(keydest, node, "key-name-hint",
+ info->keyname);
+ ret |= fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
+ ret |= fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv);
+ ret |= fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits);
+ ret |= fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits);
+ ret |= fdt_setprop_string(keydest, node, FIT_ALGO_PROP,
+ info->algo->name);
+ if (info->require_keys) {
+ fdt_setprop_string(keydest, node, "required",
+ info->require_keys);
+ }
+ BN_free(modulus);
+ BN_free(r_squared);
+ if (ret)
+ return -EIO;
+
+ return 0;
+}
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
new file mode 100644
index 0000000..6a02689
--- /dev/null
+++ b/lib/rsa/rsa-verify.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <rsa.h>
+#include <sha1.h>
+#include <asm/byteorder.h>
+#include <asm/errno.h>
+#include <asm/unaligned.h>
+
+/**
+ * struct rsa_public_key - holder for a public key
+ *
+ * An RSA public key consists of a modulus (typically called N), the inverse
+ * and R^2, where R is 2^(# key bits).
+ */
+struct rsa_public_key {
+ uint len; /* Length of modulus[] in number of uint32_t */
+ uint32_t n0inv; /* -1 / modulus[0] mod 2^32 */
+ uint32_t *modulus; /* modulus as little endian array */
+ uint32_t *rr; /* R^2 as little endian array */
+};
+
+#define UINT64_MULT32(v, multby) (((uint64_t)(v)) * ((uint32_t)(multby)))
+
+#define RSA2048_BYTES (2048 / 8)
+
+/* This is the minimum/maximum key size we support, in bits */
+#define RSA_MIN_KEY_BITS 2048
+#define RSA_MAX_KEY_BITS 2048
+
+/* This is the maximum signature length that we support, in bits */
+#define RSA_MAX_SIG_BITS 2048
+
+static const uint8_t padding_sha1_rsa2048[RSA2048_BYTES - SHA1_SUM_LEN] = {
+ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
+ 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+ 0x05, 0x00, 0x04, 0x14
+};
+
+/**
+ * subtract_modulus() - subtract modulus from the given value
+ *
+ * @key: Key containing modulus to subtract
+ * @num: Number to subtract modulus from, as little endian word array
+ */
+static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
+{
+ int64_t acc = 0;
+ uint i;
+
+ for (i = 0; i < key->len; i++) {
+ acc += (uint64_t)num[i] - key->modulus[i];
+ num[i] = (uint32_t)acc;
+ acc >>= 32;
+ }
+}
+
+/**
+ * greater_equal_modulus() - check if a value is >= modulus
+ *
+ * @key: Key containing modulus to check
+ * @num: Number to check against modulus, as little endian word array
+ * @return 0 if num < modulus, 1 if num >= modulus
+ */
+static int greater_equal_modulus(const struct rsa_public_key *key,
+ uint32_t num[])
+{
+ uint32_t i;
+
+ for (i = key->len - 1; i >= 0; i--) {
+ if (num[i] < key->modulus[i])
+ return 0;
+ if (num[i] > key->modulus[i])
+ return 1;
+ }
+
+ return 1; /* equal */
+}
+
+/**
+ * montgomery_mul_add_step() - Perform montgomery multiply-add step
+ *
+ * Operation: montgomery result[] += a * b[] / n0inv % modulus
+ *
+ * @key: RSA key
+ * @result: Place to put result, as little endian word array
+ * @a: Multiplier
+ * @b: Multiplicand, as little endian word array
+ */
+static void montgomery_mul_add_step(const struct rsa_public_key *key,
+ uint32_t result[], const uint32_t a, const uint32_t b[])
+{
+ uint64_t acc_a, acc_b;
+ uint32_t d0;
+ uint i;
+
+ acc_a = (uint64_t)a * b[0] + result[0];
+ d0 = (uint32_t)acc_a * key->n0inv;
+ acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
+ for (i = 1; i < key->len; i++) {
+ acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
+ acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
+ (uint32_t)acc_a;
+ result[i - 1] = (uint32_t)acc_b;
+ }
+
+ acc_a = (acc_a >> 32) + (acc_b >> 32);
+
+ result[i - 1] = (uint32_t)acc_a;
+
+ if (acc_a >> 32)
+ subtract_modulus(key, result);
+}
+
+/**
+ * montgomery_mul() - Perform montgomery mutitply
+ *
+ * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
+ *
+ * @key: RSA key
+ * @result: Place to put result, as little endian word array
+ * @a: Multiplier, as little endian word array
+ * @b: Multiplicand, as little endian word array
+ */
+static void montgomery_mul(const struct rsa_public_key *key,
+ uint32_t result[], uint32_t a[], const uint32_t b[])
+{
+ uint i;
+
+ for (i = 0; i < key->len; ++i)
+ result[i] = 0;
+ for (i = 0; i < key->len; ++i)
+ montgomery_mul_add_step(key, result, a[i], b);
+}
+
+/**
+ * pow_mod() - in-place public exponentiation
+ *
+ * @key: RSA key
+ * @inout: Big-endian word array containing value and result
+ */
+static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
+{
+ uint32_t *result, *ptr;
+ uint i;
+
+ /* Sanity check for stack size - key->len is in 32-bit words */
+ if (key->len > RSA_MAX_KEY_BITS / 32) {
+ debug("RSA key words %u exceeds maximum %d\n", key->len,
+ RSA_MAX_KEY_BITS / 32);
+ return -EINVAL;
+ }
+
+ uint32_t val[key->len], acc[key->len], tmp[key->len];
+ result = tmp; /* Re-use location. */
+
+ /* Convert from big endian byte array to little endian word array. */
+ for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
+ val[i] = get_unaligned_be32(ptr);
+
+ montgomery_mul(key, acc, val, key->rr); /* axx = a * RR / R mod M */
+ for (i = 0; i < 16; i += 2) {
+ montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */
+ montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */
+ }
+ montgomery_mul(key, result, acc, val); /* result = XX * a / R mod M */
+
+ /* Make sure result < mod; result is at most 1x mod too large. */
+ if (greater_equal_modulus(key, result))
+ subtract_modulus(key, result);
+
+ /* Convert to bigendian byte array */
+ for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
+ put_unaligned_be32(result[i], ptr);
+
+ return 0;
+}
+
+static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
+ const uint32_t sig_len, const uint8_t *hash)
+{
+ const uint8_t *padding;
+ int pad_len;
+ int ret;
+
+ if (!key || !sig || !hash)
+ return -EIO;
+
+ if (sig_len != (key->len * sizeof(uint32_t))) {
+ debug("Signature is of incorrect length %d\n", sig_len);
+ return -EINVAL;
+ }
+
+ /* Sanity check for stack size */
+ if (sig_len > RSA_MAX_SIG_BITS / 8) {
+ debug("Signature length %u exceeds maximum %d\n", sig_len,
+ RSA_MAX_SIG_BITS / 8);
+ return -EINVAL;
+ }
+
+ uint32_t buf[sig_len / sizeof(uint32_t)];
+
+ memcpy(buf, sig, sig_len);
+
+ ret = pow_mod(key, buf);
+ if (ret)
+ return ret;
+
+ /* Determine padding to use depending on the signature type. */
+ padding = padding_sha1_rsa2048;
+ pad_len = RSA2048_BYTES - SHA1_SUM_LEN;
+
+ /* Check pkcs1.5 padding bytes. */
+ if (memcmp(buf, padding, pad_len)) {
+ debug("In RSAVerify(): Padding check failed!\n");
+ return -EINVAL;
+ }
+
+ /* Check hash. */
+ if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
+ debug("In RSAVerify(): Hash check failed!\n");
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ dst[i] = fdt32_to_cpu(src[len - 1 - i]);
+}
+
+static int rsa_verify_with_keynode(struct image_sign_info *info,
+ const void *hash, uint8_t *sig, uint sig_len, int node)
+{
+ const void *blob = info->fdt_blob;
+ struct rsa_public_key key;
+ const void *modulus, *rr;
+ int ret;
+
+ if (node < 0) {
+ debug("%s: Skipping invalid node", __func__);
+ return -EBADF;
+ }
+ if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) {
+ debug("%s: Missing rsa,n0-inverse", __func__);
+ return -EFAULT;
+ }
+ key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
+ key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
+ modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
+ rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
+ if (!key.len || !modulus || !rr) {
+ debug("%s: Missing RSA key info", __func__);
+ return -EFAULT;
+ }
+
+ /* Sanity check for stack size */
+ if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
+ debug("RSA key bits %u outside allowed range %d..%d\n",
+ key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
+ return -EFAULT;
+ }
+ key.len /= sizeof(uint32_t) * 8;
+ uint32_t key1[key.len], key2[key.len];
+
+ key.modulus = key1;
+ key.rr = key2;
+ rsa_convert_big_endian(key.modulus, modulus, key.len);
+ rsa_convert_big_endian(key.rr, rr, key.len);
+ if (!key.modulus || !key.rr) {
+ debug("%s: Out of memory", __func__);
+ return -ENOMEM;
+ }
+
+ debug("key length %d\n", key.len);
+ ret = rsa_verify_key(&key, sig, sig_len, hash);
+ if (ret) {
+ printf("%s: RSA failed to verify: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int rsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len)
+{
+ const void *blob = info->fdt_blob;
+ uint8_t hash[SHA1_SUM_LEN];
+ int ndepth, noffset;
+ int sig_node, node;
+ char name[100];
+ sha1_context ctx;
+ int ret, i;
+
+ sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
+ if (sig_node < 0) {
+ debug("%s: No signature node found\n", __func__);
+ return -ENOENT;
+ }
+
+ sha1_starts(&ctx);
+ for (i = 0; i < region_count; i++)
+ sha1_update(&ctx, region[i].data, region[i].size);
+ sha1_finish(&ctx, hash);
+
+ /* See if we must use a particular key */
+ if (info->required_keynode != -1) {
+ ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
+ info->required_keynode);
+ if (!ret)
+ return ret;
+ }
+
+ /* Look for a key that matches our hint */
+ snprintf(name, sizeof(name), "key-%s", info->keyname);
+ node = fdt_subnode_offset(blob, sig_node, name);
+ ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node);
+ if (!ret)
+ return ret;
+
+ /* No luck, so try each of the keys in turn */
+ for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(info->fit, noffset, &ndepth)) {
+ if (ndepth == 1 && noffset != node) {
+ ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
+ noffset);
+ if (!ret)
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/lib/trace.c b/lib/trace.c
new file mode 100644
index 0000000..e7455bc
--- /dev/null
+++ b/lib/trace.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <trace.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char trace_enabled __attribute__((section(".data")));
+static char trace_inited __attribute__((section(".data")));
+
+/* The header block at the start of the trace memory area */
+struct trace_hdr {
+ int func_count; /* Total number of function call sites */
+ u64 call_count; /* Total number of tracked function calls */
+ u64 untracked_count; /* Total number of untracked function calls */
+ int funcs_used; /* Total number of functions used */
+
+ /*
+ * Call count for each function. This is indexed by the word offset
+ * of the function from gd->relocaddr
+ */
+ uintptr_t *call_accum;
+
+ /* Function trace list */
+ struct trace_call *ftrace; /* The function call records */
+ ulong ftrace_size; /* Num. of ftrace records we have space for */
+ ulong ftrace_count; /* Num. of ftrace records written */
+ ulong ftrace_too_deep_count; /* Functions that were too deep */
+
+ int depth;
+ int depth_limit;
+ int max_depth;
+};
+
+static struct trace_hdr *hdr; /* Pointer to start of trace buffer */
+
+static inline uintptr_t __attribute__((no_instrument_function))
+ func_ptr_to_num(void *func_ptr)
+{
+ uintptr_t offset = (uintptr_t)func_ptr;
+
+#ifdef CONFIG_SANDBOX
+ offset -= (uintptr_t)&_init;
+#else
+ if (gd->flags & GD_FLG_RELOC)
+ offset -= gd->relocaddr;
+ else
+ offset -= CONFIG_SYS_TEXT_BASE;
+#endif
+ return offset / FUNC_SITE_SIZE;
+}
+
+static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
+ void *caller, ulong flags)
+{
+ if (hdr->depth > hdr->depth_limit) {
+ hdr->ftrace_too_deep_count++;
+ return;
+ }
+ if (hdr->ftrace_count < hdr->ftrace_size) {
+ struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
+
+ rec->func = func_ptr_to_num(func_ptr);
+ rec->caller = func_ptr_to_num(caller);
+ rec->flags = flags | (timer_get_us() & FUNCF_TIMESTAMP_MASK);
+ }
+ hdr->ftrace_count++;
+}
+
+static void __attribute__((no_instrument_function)) add_textbase(void)
+{
+ if (hdr->ftrace_count < hdr->ftrace_size) {
+ struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
+
+ rec->func = CONFIG_SYS_TEXT_BASE;
+ rec->caller = 0;
+ rec->flags = FUNCF_TEXTBASE;
+ }
+ hdr->ftrace_count++;
+}
+
+/**
+ * This is called on every function entry
+ *
+ * We add to our tally for this function and add to the list of called
+ * functions.
+ *
+ * @param func_ptr Pointer to function being entered
+ * @param caller Pointer to function which called this function
+ */
+void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
+ void *func_ptr, void *caller)
+{
+ if (trace_enabled) {
+ int func;
+
+ add_ftrace(func_ptr, caller, FUNCF_ENTRY);
+ func = func_ptr_to_num(func_ptr);
+ if (func < hdr->func_count) {
+ hdr->call_accum[func]++;
+ hdr->call_count++;
+ } else {
+ hdr->untracked_count++;
+ }
+ hdr->depth++;
+ if (hdr->depth > hdr->depth_limit)
+ hdr->max_depth = hdr->depth;
+ }
+}
+
+/**
+ * This is called on every function exit
+ *
+ * We do nothing here.
+ *
+ * @param func_ptr Pointer to function being entered
+ * @param caller Pointer to function which called this function
+ */
+void __attribute__((no_instrument_function)) __cyg_profile_func_exit(
+ void *func_ptr, void *caller)
+{
+ if (trace_enabled) {
+ add_ftrace(func_ptr, caller, FUNCF_EXIT);
+ hdr->depth--;
+ }
+}
+
+/**
+ * Produce a list of called functions
+ *
+ * The information is written into the supplied buffer - a header followed
+ * by a list of function records.
+ *
+ * @param buff Buffer to place list into
+ * @param buff_size Size of buffer
+ * @param needed Returns size of buffer needed, which may be
+ * greater than buff_size if we ran out of space.
+ * @return 0 if ok, -1 if space was exhausted
+ */
+int trace_list_functions(void *buff, int buff_size, unsigned int *needed)
+{
+ struct trace_output_hdr *output_hdr = NULL;
+ void *end, *ptr = buff;
+ int func;
+ int upto;
+
+ end = buff ? buff + buff_size : NULL;
+
+ /* Place some header information */
+ if (ptr + sizeof(struct trace_output_hdr) < end)
+ output_hdr = ptr;
+ ptr += sizeof(struct trace_output_hdr);
+
+ /* Add information about each function */
+ for (func = upto = 0; func < hdr->func_count; func++) {
+ int calls = hdr->call_accum[func];
+
+ if (!calls)
+ continue;
+
+ if (ptr + sizeof(struct trace_output_func) < end) {
+ struct trace_output_func *stats = ptr;
+
+ stats->offset = func * FUNC_SITE_SIZE;
+ stats->call_count = calls;
+ upto++;
+ }
+ ptr += sizeof(struct trace_output_func);
+ }
+
+ /* Update the header */
+ if (output_hdr) {
+ output_hdr->rec_count = upto;
+ output_hdr->type = TRACE_CHUNK_FUNCS;
+ }
+
+ /* Work out how must of the buffer we used */
+ *needed = ptr - buff;
+ if (ptr > end)
+ return -1;
+ return 0;
+}
+
+int trace_list_calls(void *buff, int buff_size, unsigned *needed)
+{
+ struct trace_output_hdr *output_hdr = NULL;
+ void *end, *ptr = buff;
+ int rec, upto;
+ int count;
+
+ end = buff ? buff + buff_size : NULL;
+
+ /* Place some header information */
+ if (ptr + sizeof(struct trace_output_hdr) < end)
+ output_hdr = ptr;
+ ptr += sizeof(struct trace_output_hdr);
+
+ /* Add information about each call */
+ count = hdr->ftrace_count;
+ if (count > hdr->ftrace_size)
+ count = hdr->ftrace_size;
+ for (rec = upto = 0; rec < count; rec++) {
+ if (ptr + sizeof(struct trace_call) < end) {
+ struct trace_call *call = &hdr->ftrace[rec];
+ struct trace_call *out = ptr;
+
+ out->func = call->func * FUNC_SITE_SIZE;
+ out->caller = call->caller * FUNC_SITE_SIZE;
+ out->flags = call->flags;
+ upto++;
+ }
+ ptr += sizeof(struct trace_call);
+ }
+
+ /* Update the header */
+ if (output_hdr) {
+ output_hdr->rec_count = upto;
+ output_hdr->type = TRACE_CHUNK_CALLS;
+ }
+
+ /* Work out how must of the buffer we used */
+ *needed = ptr - buff;
+ if (ptr > end)
+ return -1;
+ return 0;
+}
+
+/* Print basic information about tracing */
+void trace_print_stats(void)
+{
+ ulong count;
+
+#ifndef FTRACE
+ puts("Warning: make U-Boot with FTRACE to enable function instrumenting.\n");
+ puts("You will likely get zeroed data here\n");
+#endif
+ if (!trace_inited) {
+ printf("Trace is disabled\n");
+ return;
+ }
+ print_grouped_ull(hdr->func_count, 10);
+ puts(" function sites\n");
+ print_grouped_ull(hdr->call_count, 10);
+ puts(" function calls\n");
+ print_grouped_ull(hdr->untracked_count, 10);
+ puts(" untracked function calls\n");
+ count = min(hdr->ftrace_count, hdr->ftrace_size);
+ print_grouped_ull(count, 10);
+ puts(" traced function calls");
+ if (hdr->ftrace_count > hdr->ftrace_size) {
+ printf(" (%lu dropped due to overflow)",
+ hdr->ftrace_count - hdr->ftrace_size);
+ }
+ puts("\n");
+ printf("%15d maximum observed call depth\n", hdr->max_depth);
+ printf("%15d call depth limit\n", hdr->depth_limit);
+ print_grouped_ull(hdr->ftrace_too_deep_count, 10);
+ puts(" calls not traced due to depth\n");
+}
+
+void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
+{
+ trace_enabled = enabled != 0;
+}
+
+/**
+ * Init the tracing system ready for used, and enable it
+ *
+ * @param buff Pointer to trace buffer
+ * @param buff_size Size of trace buffer
+ */
+int __attribute__((no_instrument_function)) trace_init(void *buff,
+ size_t buff_size)
+{
+ ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
+ size_t needed;
+ int was_disabled = !trace_enabled;
+
+ if (!was_disabled) {
+#ifdef CONFIG_TRACE_EARLY
+ char *end;
+ ulong used;
+
+ /*
+ * Copy over the early trace data if we have it. Disable
+ * tracing while we are doing this.
+ */
+ trace_enabled = 0;
+ hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR,
+ CONFIG_TRACE_EARLY_SIZE);
+ end = (char *)&hdr->ftrace[hdr->ftrace_count];
+ used = end - (char *)hdr;
+ printf("trace: copying %08lx bytes of early data from %x to %08lx\n",
+ used, CONFIG_TRACE_EARLY_ADDR,
+ (ulong)map_to_sysmem(buff));
+ memcpy(buff, hdr, used);
+#else
+ puts("trace: already enabled\n");
+ return -1;
+#endif
+ }
+ hdr = (struct trace_hdr *)buff;
+ needed = sizeof(*hdr) + func_count * sizeof(uintptr_t);
+ if (needed > buff_size) {
+ printf("trace: buffer size %zd bytes: at least %zd needed\n",
+ buff_size, needed);
+ return -1;
+ }
+
+ if (was_disabled)
+ memset(hdr, '\0', needed);
+ hdr->func_count = func_count;
+ hdr->call_accum = (uintptr_t *)(hdr + 1);
+
+ /* Use any remaining space for the timed function trace */
+ hdr->ftrace = (struct trace_call *)(buff + needed);
+ hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace);
+ add_textbase();
+
+ puts("trace: enabled\n");
+ hdr->depth_limit = 15;
+ trace_enabled = 1;
+ trace_inited = 1;
+ return 0;
+}
+
+#ifdef CONFIG_TRACE_EARLY
+int __attribute__((no_instrument_function)) trace_early_init(void)
+{
+ ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
+ size_t buff_size = CONFIG_TRACE_EARLY_SIZE;
+ size_t needed;
+
+ /* We can ignore additional calls to this function */
+ if (trace_enabled)
+ return 0;
+
+ hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE);
+ needed = sizeof(*hdr) + func_count * sizeof(uintptr_t);
+ if (needed > buff_size) {
+ printf("trace: buffer size is %zd bytes, at least %zd needed\n",
+ buff_size, needed);
+ return -1;
+ }
+
+ memset(hdr, '\0', needed);
+ hdr->call_accum = (uintptr_t *)(hdr + 1);
+ hdr->func_count = func_count;
+
+ /* Use any remaining space for the timed function trace */
+ hdr->ftrace = (struct trace_call *)((char *)hdr + needed);
+ hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace);
+ add_textbase();
+ hdr->depth_limit = 200;
+ printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR);
+
+ trace_enabled = 1;
+ return 0;
+}
+#endif
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 533a96b..82e5c13 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -870,3 +870,19 @@ char *simple_itoa(ulong i)
} while (i > 0);
return p + 1;
}
+
+/* We don't seem to have %'d in U-Boot */
+void print_grouped_ull(unsigned long long int_val, int digits)
+{
+ char str[21], *s;
+ int grab = 3;
+
+ digits = (digits + 2) / 3;
+ sprintf(str, "%*llu", digits * 3, int_val);
+ for (s = str; *s; s += grab) {
+ if (s != str)
+ putc(s[-1] != ' ' ? ',' : ' ');
+ printf("%.*s", grab, s);
+ grab = 3;
+ }
+}
diff --git a/test/image/test-fit.py b/test/image/test-fit.py
index c4e8211..aad9f59 100755
--- a/test/image/test-fit.py
+++ b/test/image/test-fit.py
@@ -272,12 +272,13 @@ def set_test(name):
test_name = name
print name
-def fail(msg):
+def fail(msg, stdout):
"""Raise an error with a helpful failure message
Args:
msg: Message to display
"""
+ print stdout
raise ValueError("Test '%s' failed: %s" % (test_name, msg))
def run_fit_test(mkimage, u_boot):
@@ -341,11 +342,11 @@ def run_fit_test(mkimage, u_boot):
set_test('Kernel load')
stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)
if read_file(kernel) != read_file(kernel_out):
- fail('Kernel not loaded')
+ fail('Kernel not loaded', stdout)
if read_file(control_dtb) == read_file(fdt_out):
- fail('FDT loaded but should be ignored')
+ fail('FDT loaded but should be ignored', stdout)
if read_file(ramdisk) == read_file(ramdisk_out):
- fail('Ramdisk loaded but should not be')
+ fail('Ramdisk loaded but should not be', stdout)
# Find out the offset in the FIT where U-Boot has found the FDT
line = find_matching(stdout, 'Booting using the fdt blob at ')
@@ -357,7 +358,7 @@ def run_fit_test(mkimage, u_boot):
real_fit_offset = data.find(fdt_magic, 4)
if fit_offset != real_fit_offset:
fail('U-Boot loaded FDT from offset %#x, FDT is actually at %#x' %
- (fit_offset, real_fit_offset))
+ (fit_offset, real_fit_offset), stdout)
# Now a kernel and an FDT
set_test('Kernel + FDT load')
@@ -365,11 +366,11 @@ def run_fit_test(mkimage, u_boot):
fit = make_fit(mkimage, params)
stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)
if read_file(kernel) != read_file(kernel_out):
- fail('Kernel not loaded')
+ fail('Kernel not loaded', stdout)
if read_file(control_dtb) != read_file(fdt_out):
- fail('FDT not loaded')
+ fail('FDT not loaded', stdout)
if read_file(ramdisk) == read_file(ramdisk_out):
- fail('Ramdisk loaded but should not be')
+ fail('Ramdisk loaded but should not be', stdout)
# Try a ramdisk
set_test('Kernel + FDT + Ramdisk load')
@@ -378,7 +379,7 @@ def run_fit_test(mkimage, u_boot):
fit = make_fit(mkimage, params)
stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)
if read_file(ramdisk) != read_file(ramdisk_out):
- fail('Ramdisk not loaded')
+ fail('Ramdisk not loaded', stdout)
def run_tests():
"""Parse options, run the FIT tests and print the result"""
diff --git a/test/trace/test-trace.sh b/test/trace/test-trace.sh
new file mode 100755
index 0000000..696a396
--- /dev/null
+++ b/test/trace/test-trace.sh
@@ -0,0 +1,89 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+# Simple test script for tracing with sandbox
+
+OUTPUT_DIR=sandbox
+TRACE_OPT="FTRACE=1"
+
+fail() {
+ echo "Test failed: $1"
+ if [ -n ${tmp} ]; then
+ rm ${tmp}
+ fi
+ exit 1
+}
+
+build_uboot() {
+ echo "Build sandbox"
+ OPTS="O=${OUTPUT_DIR} ${TRACE_OPT}"
+ NUM_CPUS=$(grep -c processor /proc/cpuinfo)
+ make ${OPTS} sandbox_config
+ make ${OPTS} -s -j${NUM_CPUS}
+}
+
+run_trace() {
+ echo "Run trace"
+ ./${OUTPUT_DIR}/u-boot <<END
+ trace stats
+ hash sha256 0 10000
+ trace pause
+ trace stats
+ hash sha256 0 10000
+ trace stats
+ trace resume
+ hash sha256 0 10000
+ trace pause
+ trace stats
+ reset
+END
+}
+
+check_results() {
+ echo "Check results"
+
+ # Expect sha256 to run 3 times, so we see the string 6 times
+ if [ $(grep -c sha256 ${tmp}) -ne 6 ]; then
+ fail "sha256 error"
+ fi
+
+ # 4 sets of results (output of 'trace stats')
+ if [ $(grep -c "traced function calls" ${tmp}) -ne 4 ]; then
+ fail "trace output error"
+ fi
+
+ # Check trace counts. We expect to see an increase in the number of
+ # traced function calls between each 'trace stats' command, except
+ # between calls 2 and 3, where tracing is paused.
+ # This code gets the sign of the difference between each number and
+ # its predecessor.
+ counts="$(tr -d , <${tmp} | awk '/traced function calls/ { diff = $1 - upto; upto = $1; printf "%d ", diff < 0 ? -1 : (diff > 0 ? 1 : 0)}')"
+
+ if [ "${counts}" != "1 1 0 1 " ]; then
+ fail "trace collection error: ${counts}"
+ fi
+}
+
+echo "Simple trace test / sanity check using sandbox"
+echo
+tmp="$(tempfile)"
+build_uboot
+run_trace >${tmp}
+check_results ${tmp}
+rm ${tmp}
+echo "Test passed"
diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore
new file mode 100644
index 0000000..4631242
--- /dev/null
+++ b/test/vboot/.gitignore
@@ -0,0 +1,3 @@
+/*.dtb
+/test.fit
+/dev-keys
diff --git a/test/vboot/sandbox-kernel.dts b/test/vboot/sandbox-kernel.dts
new file mode 100644
index 0000000..a1e853c
--- /dev/null
+++ b/test/vboot/sandbox-kernel.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+};
diff --git a/test/vboot/sandbox-u-boot.dts b/test/vboot/sandbox-u-boot.dts
new file mode 100644
index 0000000..a1e853c
--- /dev/null
+++ b/test/vboot/sandbox-u-boot.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+};
diff --git a/test/vboot/sign-configs.its b/test/vboot/sign-configs.its
new file mode 100644
index 0000000..db2ed79
--- /dev/null
+++ b/test/vboot/sign-configs.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ hash@1 {
+ algo = "sha1";
+ };
+ };
+ fdt@1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ hash@1 {
+ algo = "sha1";
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ sign-images = "fdt", "kernel";
+ };
+ };
+ };
+};
diff --git a/test/vboot/sign-images.its b/test/vboot/sign-images.its
new file mode 100644
index 0000000..f69326a
--- /dev/null
+++ b/test/vboot/sign-images.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ };
+ };
+ fdt@1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ signature@1 {
+ algo = "sha1,rsa2048";
+ key-name-hint = "dev";
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1 {
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ };
+ };
+};
diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh
new file mode 100755
index 0000000..c3cfade
--- /dev/null
+++ b/test/vboot/vboot_test.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Google Inc.
+#
+# Simple Verified Boot Test Script
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+
+set -e
+
+# Run U-Boot and report the result
+# Args:
+# $1: Test message
+run_uboot() {
+ echo -n "Test Verified Boot Run: $1: "
+ ${uboot} -d sandbox-u-boot.dtb >${tmp} -c '
+sb load host 0 100 test.fit;
+fdt addr 100;
+bootm 100;
+reset'
+ if ! grep -q "$2" ${tmp}; then
+ echo
+ echo "Verified boot key check failed, output follows:"
+ cat ${tmp}
+ false
+ else
+ echo "OK"
+ fi
+}
+
+echo "Simple Verified Boot Test"
+echo "========================="
+echo
+echo "Please see doc/uImage.FIT/verified-boot.txt for more information"
+echo
+
+err=0
+tmp=/tmp/vboot_test.$$
+
+dir=$(dirname $0)
+
+if [ -z ${O} ]; then
+ O=.
+fi
+O=$(readlink -f ${O})
+
+dtc="-I dts -O dtb -p 2000"
+uboot="${O}/u-boot"
+mkimage="${O}/tools/mkimage"
+keys="${dir}/dev-keys"
+echo ${mkimage} -D "${dtc}"
+
+echo "Build keys"
+mkdir -p ${keys}
+
+# Create an RSA key pair
+openssl genrsa -F4 -out ${keys}/dev.key 2048 2>/dev/null
+
+# Create a certificate containing the public key
+openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt
+
+pushd ${dir} >/dev/null
+
+# Compile our device tree files for kernel and U-Boot (CONFIG_OF_CONTROL)
+dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb
+dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
+
+# Create a number kernel image with zeroes
+head -c 5000 /dev/zero >test-kernel.bin
+
+# Build the FIT, but don't sign anything yet
+echo Build FIT with signed images
+${mkimage} -D "${dtc}" -f sign-images.its test.fit >${tmp}
+
+run_uboot "unsigned signatures:" "dev-"
+
+# Sign images with our dev keys
+echo Sign images
+${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp}
+
+run_uboot "signed images" "dev+"
+
+
+# Create a fresh .dtb without the public keys
+dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
+
+echo Build FIT with signed configuration
+${mkimage} -D "${dtc}" -f sign-configs.its test.fit >${tmp}
+
+run_uboot "unsigned config" "sha1+ OK"
+
+# Sign images with our dev keys
+echo Sign images
+${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp}
+
+run_uboot "signed config" "dev+"
+
+# Increment the first byte of the signature, which should cause failure
+sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value)
+newbyte=$(printf %x $((0x${sig:0:2} + 1)))
+sig="${newbyte} ${sig:2}"
+fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig}
+
+run_uboot "signed config with bad hash" "Bad Data Hash"
+
+popd >/dev/null
+
+echo
+if ${ok}; then
+ echo "Test passed"
+else
+ echo "Test failed"
+fi
diff --git a/tools/.gitignore b/tools/.gitignore
index 9bce719..a7fee26 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -9,6 +9,7 @@
/mxsboot
/ncb
/ncp
+/proftool
/ubsha1
/xway-swap-bytes
/*.exe
diff --git a/tools/Makefile b/tools/Makefile
index 4630f03..cc912fb 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -74,11 +74,13 @@ BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX)
+BIN_FILES-y += proftool(SFX)
# Source files which exist outside the tools directory
EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
EXT_OBJ_FILES-y += common/image.o
EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o
+EXT_OBJ_FILES-y += common/image-sig.o
EXT_OBJ_FILES-y += lib/crc32.o
EXT_OBJ_FILES-y += lib/md5.o
EXT_OBJ_FILES-y += lib/sha1.o
@@ -87,6 +89,7 @@ EXT_OBJ_FILES-y += lib/sha1.o
OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o
OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
NOPED_OBJ_FILES-y += default_image.o
+NOPED_OBJ_FILES-y += proftool.o
OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o
NOPED_OBJ_FILES-y += fit_image.o
OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o
@@ -122,6 +125,9 @@ LIBFDT_OBJ_FILES-y += fdt_rw.o
LIBFDT_OBJ_FILES-y += fdt_strerror.o
LIBFDT_OBJ_FILES-y += fdt_wip.o
+# RSA objects
+RSA_OBJ_FILES-y += rsa-sign.o
+
# Generated LCD/video logo
LOGO_H = $(OBJTREE)/include/bmp_logo.h
LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h
@@ -149,8 +155,14 @@ endif # !LOGO_BMP
HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))
HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))
HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c))
BINS := $(addprefix $(obj),$(sort $(BIN_FILES-y)))
LIBFDT_OBJS := $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
+RSA_OBJS := $(addprefix $(obj),$(RSA_OBJ_FILES-y))
+
+# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host
+FIT_SIG_OBJ_FILES := image-sig.o
+FIT_SIG_OBJS := $(addprefix $(obj),$(FIT_SIG_OBJ_FILES))
HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y))
NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y))
@@ -180,6 +192,10 @@ $(obj)bmp_logo$(SFX): $(obj)bmp_logo.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
$(HOSTSTRIP) $@
+$(obj)proftool(SFX): $(obj)proftool.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
$(obj)envcrc$(SFX): $(obj)crc32.o $(obj)env_embedded.o $(obj)envcrc.o $(obj)sha1.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
@@ -207,6 +223,7 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \
$(obj)image-fit.o \
$(obj)image.o \
$(obj)image-host.o \
+ $(FIT_SIG_OBJS) \
$(obj)imximage.o \
$(obj)kwbimage.o \
$(obj)pblimage.o \
@@ -216,8 +233,9 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \
$(obj)omapimage.o \
$(obj)sha1.o \
$(obj)ublimage.o \
- $(LIBFDT_OBJS)
- $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(LIBFDT_OBJS) \
+ $(RSA_OBJS)
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)
$(HOSTSTRIP) $@
$(obj)mk$(BOARD)spl$(SFX): $(obj)mkexynosspl.o
@@ -253,6 +271,9 @@ $(obj)%.o: $(SRCTREE)/lib/%.c
$(obj)%.o: $(SRCTREE)/lib/libfdt/%.c
$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+$(obj)%.o: $(SRCTREE)/lib/rsa/%.c
+ $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
subdirs:
ifeq ($(TOOLSUBDIRS),)
@:
diff --git a/tools/fit_image.c b/tools/fit_image.c
index cc123dd..281c2bd 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -105,9 +105,11 @@ static int fit_handle_file (struct mkimage_params *params)
{
char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
- int tfd;
+ int tfd, destfd = 0;
+ void *dest_blob = NULL;
struct stat sbuf;
void *ptr;
+ off_t destfd_size = 0;
/* Flattened Image Tree (FIT) format handling */
debug ("FIT format handling\n");
@@ -122,29 +124,44 @@ static int fit_handle_file (struct mkimage_params *params)
}
sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
- /* dtc -I dts -O dtb -p 500 datafile > tmpfile */
- sprintf (cmd, "%s %s %s > %s",
- MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
- debug ("Trying to execute \"%s\"\n", cmd);
+ /* We either compile the source file, or use the existing FIT image */
+ if (params->datafile) {
+ /* dtc -I dts -O dtb -p 500 datafile > tmpfile */
+ snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
+ MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
+ debug("Trying to execute \"%s\"\n", cmd);
+ } else {
+ snprintf(cmd, sizeof(cmd), "cp %s %s",
+ params->imagefile, tmpfile);
+ }
if (system (cmd) == -1) {
fprintf (stderr, "%s: system(%s) failed: %s\n",
params->cmdname, cmd, strerror(errno));
goto err_system;
}
+ if (params->keydest) {
+ destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
+ if (destfd < 0)
+ goto err_keydest;
+ destfd_size = sbuf.st_size;
+ }
+
tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);
if (tfd < 0)
goto err_mmap;
/* set hashes for images in the blob */
- if (fit_add_verification_data(ptr)) {
- fprintf (stderr, "%s Can't add hashes to FIT blob",
- params->cmdname);
+ if (fit_add_verification_data(params->keydir,
+ dest_blob, ptr, params->comment,
+ params->require_keys)) {
+ fprintf(stderr, "%s Can't add hashes to FIT blob\n",
+ params->cmdname);
goto err_add_hashes;
}
- /* add a timestamp at offset 0 i.e., root */
- if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) {
+ /* for first image creation, add a timestamp at offset 0 i.e., root */
+ if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
fprintf (stderr, "%s: Can't add image timestamp\n",
params->cmdname);
goto err_add_timestamp;
@@ -153,6 +170,10 @@ static int fit_handle_file (struct mkimage_params *params)
munmap ((void *)ptr, sbuf.st_size);
close (tfd);
+ if (dest_blob) {
+ munmap(dest_blob, destfd_size);
+ close(destfd);
+ }
if (rename (tmpfile, params->imagefile) == -1) {
fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
@@ -168,6 +189,9 @@ err_add_timestamp:
err_add_hashes:
munmap(ptr, sbuf.st_size);
err_mmap:
+ if (dest_blob)
+ munmap(dest_blob, destfd_size);
+err_keydest:
err_system:
unlink(tmpfile);
return -1;
diff --git a/tools/image-host.c b/tools/image-host.c
index d944d0f..932384b 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -26,12 +26,8 @@
*/
#include "mkimage.h"
-#include <bootstage.h>
#include <image.h>
-#include <sha1.h>
-#include <time.h>
-#include <u-boot/crc.h>
-#include <u-boot/md5.h>
+#include <version.h>
/**
* fit_set_hash_value - set hash value in requested has node
@@ -108,9 +104,165 @@ static int fit_image_process_hash(void *fit, const char *image_name,
}
/**
- * fit_image_add_verification_data() - calculate/set hash data for image node
+ * fit_image_write_sig() - write the signature to a FIT
*
- * This adds hash values for a component image node.
+ * This writes the signature and signer data to the FIT.
+ *
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: signature value to be set
+ * @value_len: signature value length
+ * @comment: Text comment to write (NULL for none)
+ *
+ * returns
+ * 0, on success
+ * -FDT_ERR_..., on failure
+ */
+static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
+ int value_len, const char *comment, const char *region_prop,
+ int region_proplen)
+{
+ int string_size;
+ int ret;
+
+ /*
+ * Get the current string size, before we update the FIT and add
+ * more
+ */
+ string_size = fdt_size_dt_strings(fit);
+
+ ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+ if (!ret) {
+ ret = fdt_setprop_string(fit, noffset, "signer-name",
+ "mkimage");
+ }
+ if (!ret) {
+ ret = fdt_setprop_string(fit, noffset, "signer-version",
+ PLAIN_VERSION);
+ }
+ if (comment && !ret)
+ ret = fdt_setprop_string(fit, noffset, "comment", comment);
+ if (!ret)
+ ret = fit_set_timestamp(fit, noffset, time(NULL));
+ if (region_prop && !ret) {
+ uint32_t strdata[2];
+
+ ret = fdt_setprop(fit, noffset, "hashed-nodes",
+ region_prop, region_proplen);
+ strdata[0] = 0;
+ strdata[1] = cpu_to_fdt32(string_size);
+ if (!ret) {
+ ret = fdt_setprop(fit, noffset, "hashed-strings",
+ strdata, sizeof(strdata));
+ }
+ }
+
+ return ret;
+}
+
+static int fit_image_setup_sig(struct image_sign_info *info,
+ const char *keydir, void *fit, const char *image_name,
+ int noffset, const char *require_keys)
+{
+ const char *node_name;
+ char *algo_name;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+ printf("Can't get algo property for '%s' signature node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ memset(info, '\0', sizeof(*info));
+ info->keydir = keydir;
+ info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+ info->fit = fit;
+ info->node_offset = noffset;
+ info->algo = image_get_sig_algo(algo_name);
+ info->require_keys = require_keys;
+ if (!info->algo) {
+ printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
+ algo_name, node_name, image_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_process_sig- Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For signature nodes we
+ * generate a signed hash of the supplised data and store it in the node.
+ *
+ * @keydir: Directory containing keys to use for signing
+ * @keydest: Destination FDT blob to write public keys into
+ * @fit: pointer to the FIT format image header
+ * @image_name: name of image being processes (used to display errors)
+ * @noffset: subnode offset
+ * @data: data to process
+ * @size: size of data in bytes
+ * @comment: Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_sig(const char *keydir, void *keydest,
+ void *fit, const char *image_name,
+ int noffset, const void *data, size_t size,
+ const char *comment, int require_keys)
+{
+ struct image_sign_info info;
+ struct image_region region;
+ const char *node_name;
+ uint8_t *value;
+ uint value_len;
+ int ret;
+
+ if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
+ require_keys ? "image" : NULL))
+ return -1;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ region.data = data;
+ region.size = size;
+ ret = info.algo->sign(&info, &region, 1, &value, &value_len);
+ if (ret) {
+ printf("Failed to sign '%s' signature node in '%s' image node: %d\n",
+ node_name, image_name, ret);
+
+ /* We allow keys to be missing */
+ if (ret == -ENOENT)
+ return 0;
+ return -1;
+ }
+
+ ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
+ NULL, 0);
+ if (ret) {
+ printf("Can't write signature for '%s' signature node in '%s' image node: %s\n",
+ node_name, image_name, fdt_strerror(ret));
+ return -1;
+ }
+ free(value);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+ info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+ /* Write the public key into the supplied FDT file */
+ if (keydest && info.algo->add_verify_data(&info, keydest)) {
+ printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_add_verification_data() - calculate/set verig. data for image node
+ *
+ * This adds hash and signature values for an component image node.
*
* All existing hash subnodes are checked, if algorithm property is set to
* one of the supported hash algorithms, hash value is computed and
@@ -133,11 +285,17 @@ static int fit_image_process_hash(void *fit, const char *image_name,
*
* For signature details, please see doc/uImage.FIT/signature.txt
*
+ * @keydir Directory containing *.key and *.crt files (or NULL)
+ * @keydest FDT Blob to write public keys into (NULL if none)
* @fit: Pointer to the FIT format image header
* @image_noffset: Requested component image node
+ * @comment: Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
* @return: 0 on success, <0 on failure
*/
-int fit_image_add_verification_data(void *fit, int image_noffset)
+int fit_image_add_verification_data(const char *keydir, void *keydest,
+ void *fit, int image_noffset, const char *comment,
+ int require_keys)
{
const char *image_name;
const void *data;
@@ -169,6 +327,12 @@ int fit_image_add_verification_data(void *fit, int image_noffset)
strlen(FIT_HASH_NODENAME))) {
ret = fit_image_process_hash(fit, image_name, noffset,
data, size);
+ } else if (IMAGE_ENABLE_SIGN && keydir &&
+ !strncmp(node_name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_process_sig(keydir, keydest,
+ fit, image_name, noffset, data, size,
+ comment, require_keys);
}
if (ret)
return -1;
@@ -177,9 +341,326 @@ int fit_image_add_verification_data(void *fit, int image_noffset)
return 0;
}
-int fit_add_verification_data(void *fit)
+struct strlist {
+ int count;
+ char **strings;
+};
+
+static void strlist_init(struct strlist *list)
+{
+ memset(list, '\0', sizeof(*list));
+}
+
+static void strlist_free(struct strlist *list)
+{
+ int i;
+
+ for (i = 0; i < list->count; i++)
+ free(list->strings[i]);
+ free(list->strings);
+}
+
+static int strlist_add(struct strlist *list, const char *str)
+{
+ char *dup;
+
+ dup = strdup(str);
+ list->strings = realloc(list->strings,
+ (list->count + 1) * sizeof(char *));
+ if (!list || !str)
+ return -1;
+ list->strings[list->count++] = dup;
+
+ return 0;
+}
+
+static const char *fit_config_get_image_list(void *fit, int noffset,
+ int *lenp, int *allow_missingp)
+{
+ static const char default_list[] = FIT_KERNEL_PROP "\0"
+ FIT_FDT_PROP;
+ const char *prop;
+
+ /* If there is an "image" property, use that */
+ prop = fdt_getprop(fit, noffset, "sign-images", lenp);
+ if (prop) {
+ *allow_missingp = 0;
+ return *lenp ? prop : NULL;
+ }
+
+ /* Default image list */
+ *allow_missingp = 1;
+ *lenp = sizeof(default_list);
+
+ return default_list;
+}
+
+static int fit_config_get_hash_list(void *fit, int conf_noffset,
+ int sig_offset, struct strlist *node_inc)
+{
+ int allow_missing;
+ const char *prop, *iname, *end;
+ const char *conf_name, *sig_name;
+ char name[200], path[200];
+ int image_count;
+ int ret, len;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+ sig_name = fit_get_name(fit, sig_offset, NULL);
+
+ /*
+ * Build a list of nodes we need to hash. We always need the root
+ * node and the configuration.
+ */
+ strlist_init(node_inc);
+ snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
+ if (strlist_add(node_inc, "/") ||
+ strlist_add(node_inc, name))
+ goto err_mem;
+
+ /* Get a list of images that we intend to sign */
+ prop = fit_config_get_image_list(fit, conf_noffset, &len,
+ &allow_missing);
+ if (!prop)
+ return 0;
+
+ /* Locate the images */
+ end = prop + len;
+ image_count = 0;
+ for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+ int noffset;
+ int image_noffset;
+ int hash_count;
+
+ image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+ iname);
+ if (image_noffset < 0) {
+ printf("Failed to find image '%s' in configuration '%s/%s'\n",
+ iname, conf_name, sig_name);
+ if (allow_missing)
+ continue;
+
+ return -ENOENT;
+ }
+
+ ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
+ if (ret < 0)
+ goto err_path;
+ if (strlist_add(node_inc, path))
+ goto err_mem;
+
+ snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH,
+ conf_name);
+
+ /* Add all this image's hashes */
+ hash_count = 0;
+ for (noffset = fdt_first_subnode(fit, image_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ if (strncmp(name, FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME)))
+ continue;
+ ret = fdt_get_path(fit, noffset, path, sizeof(path));
+ if (ret < 0)
+ goto err_path;
+ if (strlist_add(node_inc, path))
+ goto err_mem;
+ hash_count++;
+ }
+
+ if (!hash_count) {
+ printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
+ conf_name, sig_name, iname);
+ return -ENOMSG;
+ }
+
+ image_count++;
+ }
+
+ if (!image_count) {
+ printf("Failed to find any images for configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMSG;
+ }
+
+ return 0;
+
+err_mem:
+ printf("Out of memory processing configuration '%s/%s'\n", conf_name,
+ sig_name);
+ return -ENOMEM;
+
+err_path:
+ printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
+ iname, conf_name, sig_name, fdt_strerror(ret));
+ return -ENOENT;
+}
+
+static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
+ struct image_region **regionp, int *region_countp,
+ char **region_propp, int *region_proplen)
{
- int images_noffset;
+ char * const exc_prop[] = {"data"};
+ struct strlist node_inc;
+ struct image_region *region;
+ struct fdt_region fdt_regions[100];
+ const char *conf_name, *sig_name;
+ char path[200];
+ int count, i;
+ char *region_prop;
+ int ret, len;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+ sig_name = fit_get_name(fit, conf_noffset, NULL);
+ debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
+
+ /* Get a list of nodes we want to hash */
+ ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc);
+ if (ret)
+ return ret;
+
+ /* Get a list of regions to hash */
+ count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
+ exc_prop, ARRAY_SIZE(exc_prop),
+ fdt_regions, ARRAY_SIZE(fdt_regions),
+ path, sizeof(path), 1);
+ if (count < 0) {
+ printf("Failed to hash configuration '%s/%s': %s\n", conf_name,
+ sig_name, fdt_strerror(ret));
+ return -EIO;
+ }
+ if (count == 0) {
+ printf("No data to hash for configuration '%s/%s': %s\n",
+ conf_name, sig_name, fdt_strerror(ret));
+ return -EINVAL;
+ }
+
+ /* Build our list of data blocks */
+ region = fit_region_make_list(fit, fdt_regions, count, NULL);
+ if (!region) {
+ printf("Out of memory hashing configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMEM;
+ }
+
+ /* Create a list of all hashed properties */
+ debug("Hash nodes:\n");
+ for (i = len = 0; i < node_inc.count; i++) {
+ debug(" %s\n", node_inc.strings[i]);
+ len += strlen(node_inc.strings[i]) + 1;
+ }
+ region_prop = malloc(len);
+ if (!region_prop) {
+ printf("Out of memory setting up regions for configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMEM;
+ }
+ for (i = len = 0; i < node_inc.count;
+ len += strlen(node_inc.strings[i]) + 1, i++)
+ strcpy(region_prop + len, node_inc.strings[i]);
+ strlist_free(&node_inc);
+
+ *region_countp = count;
+ *regionp = region;
+ *region_propp = region_prop;
+ *region_proplen = len;
+
+ return 0;
+}
+
+static int fit_config_process_sig(const char *keydir, void *keydest,
+ void *fit, const char *conf_name, int conf_noffset,
+ int noffset, const char *comment, int require_keys)
+{
+ struct image_sign_info info;
+ const char *node_name;
+ struct image_region *region;
+ char *region_prop;
+ int region_proplen;
+ int region_count;
+ uint8_t *value;
+ uint value_len;
+ int ret;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (fit_config_get_data(fit, conf_noffset, noffset, &region,
+ &region_count, &region_prop, &region_proplen))
+ return -1;
+
+ if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
+ require_keys ? "conf" : NULL))
+ return -1;
+
+ ret = info.algo->sign(&info, region, region_count, &value, &value_len);
+ free(region);
+ if (ret) {
+ printf("Failed to sign '%s' signature node in '%s' conf node\n",
+ node_name, conf_name);
+
+ /* We allow keys to be missing */
+ if (ret == -ENOENT)
+ return 0;
+ return -1;
+ }
+
+ if (fit_image_write_sig(fit, noffset, value, value_len, comment,
+ region_prop, region_proplen)) {
+ printf("Can't write signature for '%s' signature node in '%s' conf node\n",
+ node_name, conf_name);
+ return -1;
+ }
+ free(value);
+ free(region_prop);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+ info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+ /* Write the public key into the supplied FDT file */
+ if (keydest && info.algo->add_verify_data(&info, keydest)) {
+ printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+ node_name, conf_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_config_add_verification_data(const char *keydir, void *keydest,
+ void *fit, int conf_noffset, const char *comment,
+ int require_keys)
+{
+ const char *conf_name;
+ int noffset;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+
+ /* Process all hash subnodes of the configuration node */
+ for (noffset = fdt_first_subnode(fit, conf_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *node_name;
+ int ret = 0;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (!strncmp(node_name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_config_process_sig(keydir, keydest,
+ fit, conf_name, conf_noffset, noffset, comment,
+ require_keys);
+ }
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+ const char *comment, int require_keys)
+{
+ int images_noffset, confs_noffset;
int noffset;
int ret;
@@ -199,7 +680,31 @@ int fit_add_verification_data(void *fit)
* Direct child node of the images parent node,
* i.e. component image node.
*/
- ret = fit_image_add_verification_data(fit, noffset);
+ ret = fit_image_add_verification_data(keydir, keydest,
+ fit, noffset, comment, require_keys);
+ if (ret)
+ return ret;
+ }
+
+ /* If there are no keys, we can't sign configurations */
+ if (!IMAGE_ENABLE_SIGN || !keydir)
+ return 0;
+
+ /* Find configurations parent node offset */
+ confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(confs_noffset));
+ return -ENOENT;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (noffset = fdt_first_subnode(fit, confs_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ ret = fit_config_add_verification_data(keydir, keydest,
+ fit, noffset, comment,
+ require_keys);
if (ret)
return ret;
}
diff --git a/tools/mkimage.c b/tools/mkimage.c
index e43b09f..d312844 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -183,6 +183,11 @@ main (int argc, char **argv)
genimg_get_arch_id (*++argv)) < 0)
usage ();
goto NXTARG;
+ case 'c':
+ if (--argc <= 0)
+ usage();
+ params.comment = *++argv;
+ goto NXTARG;
case 'C':
if ((--argc <= 0) ||
(params.comp =
@@ -240,19 +245,34 @@ main (int argc, char **argv)
case 'f':
if (--argc <= 0)
usage ();
+ params.datafile = *++argv;
+ /* no break */
+ case 'F':
/*
* The flattened image tree (FIT) format
* requires a flattened device tree image type
*/
params.type = IH_TYPE_FLATDT;
- params.datafile = *++argv;
params.fflag = 1;
goto NXTARG;
+ case 'k':
+ if (--argc <= 0)
+ usage();
+ params.keydir = *++argv;
+ goto NXTARG;
+ case 'K':
+ if (--argc <= 0)
+ usage();
+ params.keydest = *++argv;
+ goto NXTARG;
case 'n':
if (--argc <= 0)
usage ();
params.imagename = *++argv;
goto NXTARG;
+ case 'r':
+ params.require_keys = 1;
+ break;
case 'R':
if (--argc <= 0)
usage();
@@ -623,8 +643,20 @@ usage ()
" -d ==> use image data from 'datafile'\n"
" -x ==> set XIP (execute in place)\n",
params.cmdname);
- fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n",
+ fprintf(stderr, " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
params.cmdname);
+ fprintf(stderr, " -D => set options for device tree compiler\n"
+ " -f => input filename for FIT source\n");
+#ifdef CONFIG_FIT_SIGNATURE
+ fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
+ " -k => set directory containing private keys\n"
+ " -K => write public keys to this .dtb file\n"
+ " -c => add comment in signature node\n"
+ " -F => re-sign existing FIT image\n"
+ " -r => mark keys used as 'required' in dtb\n");
+#else
+ fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
+#endif
fprintf (stderr, " %s -V ==> print version information and exit\n",
params.cmdname);
diff --git a/tools/mkimage.h b/tools/mkimage.h
index 03c6c8f..1d9984e 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -87,6 +87,10 @@ struct mkimage_params {
char *datafile;
char *imagefile;
char *cmdname;
+ const char *keydir; /* Directory holding private keys */
+ const char *keydest; /* Destination .dtb for public key */
+ const char *comment; /* Comment to add to signature node */
+ int require_keys; /* 1 to mark signing keys as 'required' */
};
/*
diff --git a/tools/proftool.c b/tools/proftool.c
new file mode 100644
index 0000000..a48ed28
--- /dev/null
+++ b/tools/proftool.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Decode and dump U-Boot profiling information */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <compiler.h>
+#include <trace.h>
+
+#define MAX_LINE_LEN 500
+
+enum {
+ FUNCF_TRACE = 1 << 0, /* Include this function in trace */
+};
+
+struct func_info {
+ unsigned long offset;
+ const char *name;
+ unsigned long code_size;
+ unsigned long call_count;
+ unsigned flags;
+ /* the section this function is in */
+ struct objsection_info *objsection;
+};
+
+enum trace_line_type {
+ TRACE_LINE_INCLUDE,
+ TRACE_LINE_EXCLUDE,
+};
+
+struct trace_configline_info {
+ struct trace_configline_info *next;
+ enum trace_line_type type;
+ const char *name; /* identifier name / wildcard */
+ regex_t regex; /* Regex to use if name starts with / */
+};
+
+/* The contents of the trace config file */
+struct trace_configline_info *trace_config_head;
+
+struct func_info *func_list;
+int func_count;
+struct trace_call *call_list;
+int call_count;
+int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */
+unsigned long text_offset; /* text address of first function */
+
+static void outf(int level, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 2, 3)));
+#define error(fmt, b...) outf(0, fmt, ##b)
+#define warn(fmt, b...) outf(1, fmt, ##b)
+#define notice(fmt, b...) outf(2, fmt, ##b)
+#define info(fmt, b...) outf(3, fmt, ##b)
+#define debug(fmt, b...) outf(4, fmt, ##b)
+
+
+static void outf(int level, const char *fmt, ...)
+{
+ if (verbose >= level) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ }
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: proftool -cds -v3 <cmd> <profdata>\n"
+ "\n"
+ "Commands\n"
+ " dump-ftrace\t\tDump out textual data in ftrace format\n"
+ "\n"
+ "Options:\n"
+ " -m <map>\tSpecify Systen.map file\n"
+ " -t <trace>\tSpecific trace data file (from U-Boot)\n"
+ " -v <0-4>\tSpecify verbosity\n");
+ exit(EXIT_FAILURE);
+}
+
+static int h_cmp_offset(const void *v1, const void *v2)
+{
+ const struct func_info *f1 = v1, *f2 = v2;
+
+ return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE);
+}
+
+static int read_system_map(FILE *fin)
+{
+ unsigned long offset, start = 0;
+ struct func_info *func;
+ char buff[MAX_LINE_LEN];
+ char symtype;
+ char symname[MAX_LINE_LEN + 1];
+ int linenum;
+ int alloced;
+
+ for (linenum = 1, alloced = func_count = 0;; linenum++) {
+ int fields = 0;
+
+ if (fgets(buff, sizeof(buff), fin))
+ fields = sscanf(buff, "%lx %c %100s\n", &offset,
+ &symtype, symname);
+ if (fields == 2) {
+ continue;
+ } else if (feof(fin)) {
+ break;
+ } else if (fields < 2) {
+ error("Map file line %d: invalid format\n", linenum);
+ return 1;
+ }
+
+ /* Must be a text symbol */
+ symtype = tolower(symtype);
+ if (symtype != 't' && symtype != 'w')
+ continue;
+
+ if (func_count == alloced) {
+ alloced += 256;
+ func_list = realloc(func_list,
+ sizeof(struct func_info) * alloced);
+ assert(func_list);
+ }
+ if (!func_count)
+ start = offset;
+
+ func = &func_list[func_count++];
+ memset(func, '\0', sizeof(*func));
+ func->offset = offset - start;
+ func->name = strdup(symname);
+ func->flags = FUNCF_TRACE; /* trace by default */
+
+ /* Update previous function's code size */
+ if (func_count > 1)
+ func[-1].code_size = func->offset - func[-1].offset;
+ }
+ notice("%d functions found in map file\n", func_count);
+ text_offset = start;
+ return 0;
+}
+
+static int read_data(FILE *fin, void *buff, int size)
+{
+ int err;
+
+ err = fread(buff, 1, size, fin);
+ if (!err)
+ return 1;
+ if (err != size) {
+ error("Cannot read profile file at pos %ld\n", ftell(fin));
+ return -1;
+ }
+ return 0;
+}
+
+static struct func_info *find_func_by_offset(uint32_t offset)
+{
+ struct func_info key, *found;
+
+ key.offset = offset;
+ found = bsearch(&key, func_list, func_count, sizeof(struct func_info),
+ h_cmp_offset);
+
+ return found;
+}
+
+/* This finds the function which contains the given offset */
+static struct func_info *find_caller_by_offset(uint32_t offset)
+{
+ int low; /* least function that could be a match */
+ int high; /* greated function that could be a match */
+ struct func_info key;
+
+ low = 0;
+ high = func_count - 1;
+ key.offset = offset;
+ while (high > low + 1) {
+ int mid = (low + high) / 2;
+ int result;
+
+ result = h_cmp_offset(&key, &func_list[mid]);
+ if (result > 0)
+ low = mid;
+ else if (result < 0)
+ high = mid;
+ else
+ return &func_list[mid];
+ }
+
+ return low >= 0 ? &func_list[low] : NULL;
+}
+
+static int read_calls(FILE *fin, int count)
+{
+ struct trace_call *call_data;
+ int i;
+
+ notice("call count: %d\n", count);
+ call_list = (struct trace_call *)calloc(count, sizeof(*call_data));
+ if (!call_list) {
+ error("Cannot allocate call_list\n");
+ return -1;
+ }
+ call_count = count;
+
+ call_data = call_list;
+ for (i = 0; i < count; i++, call_data++) {
+ if (read_data(fin, call_data, sizeof(*call_data)))
+ return 1;
+ }
+ return 0;
+}
+
+static int read_profile(FILE *fin, int *not_found)
+{
+ struct trace_output_hdr hdr;
+
+ *not_found = 0;
+ while (!feof(fin)) {
+ int err;
+
+ err = read_data(fin, &hdr, sizeof(hdr));
+ if (err == 1)
+ break; /* EOF */
+ else if (err)
+ return 1;
+
+ switch (hdr.type) {
+ case TRACE_CHUNK_FUNCS:
+ /* Ignored at present */
+ break;
+
+ case TRACE_CHUNK_CALLS:
+ if (read_calls(fin, hdr.rec_count))
+ return 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int read_map_file(const char *fname)
+{
+ FILE *fmap;
+ int err = 0;
+
+ fmap = fopen(fname, "r");
+ if (!fmap) {
+ error("Cannot open map file '%s'\n", fname);
+ return 1;
+ }
+ if (fmap) {
+ err = read_system_map(fmap);
+ fclose(fmap);
+ }
+ return err;
+}
+
+static int read_profile_file(const char *fname)
+{
+ int not_found = INT_MAX;
+ FILE *fprof;
+ int err;
+
+ fprof = fopen(fname, "rb");
+ if (!fprof) {
+ error("Cannot open profile data file '%s'\n",
+ fname);
+ return 1;
+ } else {
+ err = read_profile(fprof, &not_found);
+ fclose(fprof);
+ if (err)
+ return err;
+
+ if (not_found) {
+ warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n",
+ not_found);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int regex_report_error(regex_t *regex, int err, const char *op,
+ const char *name)
+{
+ char buf[200];
+
+ regerror(err, regex, buf, sizeof(buf));
+ error("Regex error '%s' in %s '%s'\n", buf, op, name);
+ return -1;
+}
+
+static void check_trace_config_line(struct trace_configline_info *item)
+{
+ struct func_info *func, *end;
+ int err;
+
+ debug("Checking trace config line '%s'\n", item->name);
+ for (func = func_list, end = func + func_count; func < end; func++) {
+ err = regexec(&item->regex, func->name, 0, NULL, 0);
+ debug(" - regex '%s', string '%s': %d\n", item->name,
+ func->name, err);
+ if (err == REG_NOMATCH)
+ continue;
+
+ if (err != REG_NOERROR) {
+ regex_report_error(&item->regex, err, "match",
+ item->name);
+ break;
+ }
+
+ /* It matches, so perform the action */
+ switch (item->type) {
+ case TRACE_LINE_INCLUDE:
+ info(" include %s at %lx\n", func->name,
+ text_offset + func->offset);
+ func->flags |= FUNCF_TRACE;
+ break;
+
+ case TRACE_LINE_EXCLUDE:
+ info(" exclude %s at %lx\n", func->name,
+ text_offset + func->offset);
+ func->flags &= ~FUNCF_TRACE;
+ break;
+ }
+ }
+}
+
+static void check_trace_config(void)
+{
+ struct trace_configline_info *line;
+
+ for (line = trace_config_head; line; line = line->next)
+ check_trace_config_line(line);
+}
+
+/**
+ * Check the functions to see if they each have an objsection. If not, then
+ * the linker must have eliminated them.
+ */
+static void check_functions(void)
+{
+ struct func_info *func, *end;
+ unsigned long removed_code_size = 0;
+ int not_found = 0;
+
+ /* Look for missing functions */
+ for (func = func_list, end = func + func_count; func < end; func++) {
+ if (!func->objsection) {
+ removed_code_size += func->code_size;
+ not_found++;
+ }
+ }
+
+ /* Figure out what functions we want to trace */
+ check_trace_config();
+
+ warn("%d functions removed by linker, %ld code size\n",
+ not_found, removed_code_size);
+}
+
+static int read_trace_config(FILE *fin)
+{
+ char buff[200];
+ int linenum = 0;
+ struct trace_configline_info **tailp = &trace_config_head;
+
+ while (fgets(buff, sizeof(buff), fin)) {
+ int len = strlen(buff);
+ struct trace_configline_info *line;
+ char *saveptr;
+ char *s, *tok;
+ int err;
+
+ linenum++;
+ if (len && buff[len - 1] == '\n')
+ buff[len - 1] = '\0';
+
+ /* skip blank lines and comments */
+ for (s = buff; *s == ' ' || *s == '\t'; s++)
+ ;
+ if (!*s || *s == '#')
+ continue;
+
+ line = (struct trace_configline_info *)calloc(1,
+ sizeof(*line));
+ if (!line) {
+ error("Cannot allocate config line\n");
+ return -1;
+ }
+
+ tok = strtok_r(s, " \t", &saveptr);
+ if (!tok) {
+ error("Invalid trace config data on line %d\n",
+ linenum);
+ return -1;
+ }
+ if (0 == strcmp(tok, "include-func")) {
+ line->type = TRACE_LINE_INCLUDE;
+ } else if (0 == strcmp(tok, "exclude-func")) {
+ line->type = TRACE_LINE_EXCLUDE;
+ } else {
+ error("Unknown command in trace config data line %d\n",
+ linenum);
+ return -1;
+ }
+
+ tok = strtok_r(NULL, " \t", &saveptr);
+ if (!tok) {
+ error("Missing pattern in trace config data line %d\n",
+ linenum);
+ return -1;
+ }
+
+ err = regcomp(&line->regex, tok, REG_NOSUB);
+ if (err) {
+ free(line);
+ return regex_report_error(&line->regex, err, "compile",
+ tok);
+ }
+
+ /* link this new one to the end of the list */
+ line->name = strdup(tok);
+ line->next = NULL;
+ *tailp = line;
+ tailp = &line->next;
+ }
+
+ if (!feof(fin)) {
+ error("Cannot read from trace config file at position %ld\n",
+ ftell(fin));
+ return -1;
+ }
+ return 0;
+}
+
+static int read_trace_config_file(const char *fname)
+{
+ FILE *fin;
+ int err;
+
+ fin = fopen(fname, "r");
+ if (!fin) {
+ error("Cannot open trace_config file '%s'\n", fname);
+ return -1;
+ }
+ err = read_trace_config(fin);
+ fclose(fin);
+ return err;
+}
+
+static void out_func(ulong func_offset, int is_caller, const char *suffix)
+{
+ struct func_info *func;
+
+ func = (is_caller ? find_caller_by_offset : find_func_by_offset)
+ (func_offset);
+
+ if (func)
+ printf("%s%s", func->name, suffix);
+ else
+ printf("%lx%s", func_offset, suffix);
+}
+
+/*
+ * # tracer: function
+ * #
+ * # TASK-PID CPU# TIMESTAMP FUNCTION
+ * # | | | | |
+ * # bash-4251 [01] 10152.583854: path_put <-path_walk
+ * # bash-4251 [01] 10152.583855: dput <-path_put
+ * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput
+ */
+static int make_ftrace(void)
+{
+ struct trace_call *call;
+ int missing_count = 0, skip_count = 0;
+ int i;
+
+ printf("# tracer: ftrace\n"
+ "#\n"
+ "# TASK-PID CPU# TIMESTAMP FUNCTION\n"
+ "# | | | | |\n");
+ for (i = 0, call = call_list; i < call_count; i++, call++) {
+ struct func_info *func = find_func_by_offset(call->func);
+ ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
+
+ if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY &&
+ TRACE_CALL_TYPE(call) != FUNCF_EXIT)
+ continue;
+ if (!func) {
+ warn("Cannot find function at %lx\n",
+ text_offset + call->func);
+ missing_count++;
+ continue;
+ }
+
+ if (!(func->flags & FUNCF_TRACE)) {
+ debug("Funcion '%s' is excluded from trace\n",
+ func->name);
+ skip_count++;
+ continue;
+ }
+
+ printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
+ time / 1000000, time % 1000000);
+
+ out_func(call->func, 0, " <- ");
+ out_func(call->caller, 1, "\n");
+ }
+ info("ftrace: %d functions not found, %d excluded\n", missing_count,
+ skip_count);
+
+ return 0;
+}
+
+static int prof_tool(int argc, char * const argv[],
+ const char *prof_fname, const char *map_fname,
+ const char *trace_config_fname)
+{
+ int err = 0;
+
+ if (read_map_file(map_fname))
+ return -1;
+ if (prof_fname && read_profile_file(prof_fname))
+ return -1;
+ if (trace_config_fname && read_trace_config_file(trace_config_fname))
+ return -1;
+
+ check_functions();
+
+ for (; argc; argc--, argv++) {
+ const char *cmd = *argv;
+
+ if (0 == strcmp(cmd, "dump-ftrace"))
+ err = make_ftrace();
+ else
+ warn("Unknown command '%s'\n", cmd);
+ }
+
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *map_fname = "System.map";
+ const char *prof_fname = NULL;
+ const char *trace_config_fname = NULL;
+ int opt;
+
+ verbose = 2;
+ while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
+ switch (opt) {
+ case 'm':
+ map_fname = optarg;
+ break;
+
+ case 'p':
+ prof_fname = optarg;
+ break;
+
+ case 't':
+ trace_config_fname = optarg;
+ break;
+
+ case 'v':
+ verbose = atoi(optarg);
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind; argv += optind;
+ if (argc < 1)
+ usage();
+
+ debug("Debug enabled\n");
+ return prof_tool(argc, argv, prof_fname, map_fname,
+ trace_config_fname);
+}