diff options
67 files changed, 2043 insertions, 198 deletions
@@ -1,5 +1,5 @@ VERSION = 2019 -PATCHLEVEL = 04 +PATCHLEVEL = 05 SUBLEVEL = 0 EXTRAVERSION = NAME = None diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig index 2577103293..f8abbccfca 100644 --- a/arch/arm/cpu/Kconfig +++ b/arch/arm/cpu/Kconfig @@ -86,6 +86,7 @@ config CPU_V8 select CPU_64v8 select CPU_SUPPORTS_64BIT_KERNEL select ARM_EXCEPTIONS + select GENERIC_FIND_NEXT_BIT config CPU_XSC3 bool diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S index 7a1c5c0189..6a8aff8bb1 100644 --- a/arch/arm/cpu/cache-armv7.S +++ b/arch/arm/cpu/cache-armv7.S @@ -83,7 +83,10 @@ hierarchical: ands r3, r0, #0x7000000 @ extract loc from clidr mov r3, r3, lsr #23 @ left align loc bit field beq finished @ if loc is 0, then no need to clean - mov r12, #0 @ start clean at cache level 0 + cmp r8, #0 +THUMB( ite eq ) + moveq r12, #0 + subne r12, r3, #2 @ start invalidate at outmost cache level loop1: add r2, r12, r12, lsr #1 @ work out 3x current cache level mov r1, r0, lsr r2 @ extract cache type bits from clidr @@ -118,8 +121,16 @@ THUMB( ite eq ) subs r7, r7, #1 @ decrement the index bge loop2 skip: + cmp r8, #0 + bne inval_check add r12, r12, #2 @ increment cache number cmp r3, r12 + b loop_end_check +inval_check: + cmp r12, #0 + sub r12, r12, #2 @ decrement cache number +loop_end_check: + dsb @ work-around Cortex-A7 erratum 814220 bgt loop1 finished: ldmfd sp!, {r4-r11} diff --git a/arch/arm/cpu/lowlevel_64.S b/arch/arm/cpu/lowlevel_64.S index af1cd8b5bc..6a23132ed1 100644 --- a/arch/arm/cpu/lowlevel_64.S +++ b/arch/arm/cpu/lowlevel_64.S @@ -12,6 +12,13 @@ ENTRY(arm_cpu_lowlevel_init) orr x0, x0, #(1 << 10) /* 64-bit EL2 */ msr scr_el3, x0 msr cptr_el3, xzr + + mrs x0, sctlr_el3 + ldr x1, =SCTLR_ELx_FLAGS + bic x0, x0, x1 + msr sctlr_el3, x0 + isb + b done 2: diff --git a/arch/arm/cpu/mmu-early.c b/arch/arm/cpu/mmu-early.c index d39a03ed95..2f5876fc46 100644 --- a/arch/arm/cpu/mmu-early.c +++ b/arch/arm/cpu/mmu-early.c @@ -5,17 +5,20 @@ #include <asm/memory.h> #include <asm/system.h> #include <asm/cache.h> +#include <asm-generic/sections.h> #include "mmu.h" static uint32_t *ttb; -static void map_cachable(unsigned long start, unsigned long size) +static inline void map_region(unsigned long start, unsigned long size, + uint64_t flags) + { start = ALIGN_DOWN(start, SZ_1M); size = ALIGN(size, SZ_1M); - create_sections(ttb, start, start + size - 1, PMD_SECT_DEF_CACHED); + create_sections(ttb, start, start + size - 1, flags); } void mmu_early_enable(unsigned long membase, unsigned long memsize, @@ -28,9 +31,27 @@ void mmu_early_enable(unsigned long membase, unsigned long memsize, set_ttbr(ttb); set_domain(DOMAIN_MANAGER); + /* + * This marks the whole address space as uncachable as well as + * unexecutable if possible + */ create_flat_mapping(ttb); - map_cachable(membase, memsize); + /* + * There can be SoCs that have a section shared between device memory + * and the on-chip RAM hosting the PBL. Thus mark this section + * uncachable, but executable. + * On such SoCs, executing from OCRAM could cause the instruction + * prefetcher to speculatively access that device memory, triggering + * potential errant behavior. + * + * If your SoC has such a memory layout, you should rewrite the code + * here to map the OCRAM page-wise. + */ + map_region((unsigned long)_stext, _etext - _stext, PMD_SECT_DEF_UNCACHED); + + /* maps main memory as cachable */ + map_region(membase, memsize, PMD_SECT_DEF_CACHED); __mmu_cache_on(); } diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c index 29816ad563..123e19e9e5 100644 --- a/arch/arm/cpu/mmu.c +++ b/arch/arm/cpu/mmu.c @@ -34,7 +34,6 @@ #include "mmu.h" -#define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED) #define PTRS_PER_PTE (PGDIR_SIZE / PAGE_SIZE) #define ARCH_MAP_WRITECOMBINE ((unsigned)-1) @@ -58,11 +57,13 @@ static inline void tlb_invalidate(void) } #define PTE_FLAGS_CACHED_V7 (PTE_EXT_TEX(1) | PTE_BUFFERABLE | PTE_CACHEABLE) -#define PTE_FLAGS_WC_V7 PTE_EXT_TEX(1) -#define PTE_FLAGS_UNCACHED_V7 (0) +#define PTE_FLAGS_WC_V7 (PTE_EXT_TEX(1) | PTE_EXT_XN) +#define PTE_FLAGS_UNCACHED_V7 PTE_EXT_XN #define PTE_FLAGS_CACHED_V4 (PTE_SMALL_AP_UNO_SRW | PTE_BUFFERABLE | PTE_CACHEABLE) #define PTE_FLAGS_UNCACHED_V4 PTE_SMALL_AP_UNO_SRW -#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE) +#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ + PMD_SECT_XN) +#define PGD_FLAGS_UNCACHED_V7 (PMD_SECT_DEF_UNCACHED | PMD_SECT_XN) /* * PTE flags to set cached and uncached areas. @@ -72,6 +73,7 @@ static uint32_t pte_flags_cached; static uint32_t pte_flags_wc; static uint32_t pte_flags_uncached; static uint32_t pgd_flags_wc; +static uint32_t pgd_flags_uncached; #define PTE_MASK ((1 << 12) - 1) @@ -164,7 +166,7 @@ int arch_remap_range(void *start, size_t size, unsigned flags) break; case MAP_UNCACHED: pte_flags = pte_flags_uncached; - pgd_flags = PMD_SECT_DEF_UNCACHED; + pgd_flags = pgd_flags_uncached; break; case ARCH_MAP_WRITECOMBINE: pte_flags = pte_flags_wc; @@ -247,7 +249,7 @@ void *map_io_sections(unsigned long phys, void *_start, size_t size) unsigned long start = (unsigned long)_start, sec; for (sec = start; sec < start + size; sec += PGDIR_SIZE, phys += PGDIR_SIZE) - ttb[pgd_index(sec)] = phys | PMD_SECT_DEF_UNCACHED; + ttb[pgd_index(sec)] = phys | pgd_flags_uncached; dma_flush_range(ttb, 0x4000); tlb_invalidate(); @@ -411,11 +413,13 @@ void __mmu_init(bool mmu_on) pte_flags_cached = PTE_FLAGS_CACHED_V7; pte_flags_wc = PTE_FLAGS_WC_V7; pgd_flags_wc = PGD_FLAGS_WC_V7; + pgd_flags_uncached = PGD_FLAGS_UNCACHED_V7; pte_flags_uncached = PTE_FLAGS_UNCACHED_V7; } else { pte_flags_cached = PTE_FLAGS_CACHED_V4; pte_flags_wc = PTE_FLAGS_UNCACHED_V4; pgd_flags_wc = PMD_SECT_DEF_UNCACHED; + pgd_flags_uncached = PMD_SECT_DEF_UNCACHED; pte_flags_uncached = PTE_FLAGS_UNCACHED_V4; } diff --git a/arch/arm/cpu/mmu.h b/arch/arm/cpu/mmu.h index 338728aacd..c911ee209f 100644 --- a/arch/arm/cpu/mmu.h +++ b/arch/arm/cpu/mmu.h @@ -3,6 +3,7 @@ #include <asm/pgtable.h> #include <linux/sizes.h> +#include <asm/system_info.h> #include "mmu-common.h" @@ -62,8 +63,13 @@ create_sections(uint32_t *ttb, unsigned long first, static inline void create_flat_mapping(uint32_t *ttb) { + unsigned int flags = PMD_SECT_DEF_UNCACHED; + + if (cpu_architecture() >= CPU_ARCH_ARMv7) + flags |= PMD_SECT_XN; + /* create a flat mapping using 1MiB sections */ - create_sections(ttb, 0, 0xffffffff, PMD_SECT_DEF_UNCACHED); + create_sections(ttb, 0, 0xffffffff, flags); } #endif /* __ARM_MMU_H */ diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index 348a76b2c1..d8a4d9b667 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -82,6 +82,12 @@ static inline int test_bit(int nr, const void * addr) #define test_and_clear_bit(x, y) __test_and_clear_bit(x, y) #define test_and_change_bit(x, y) __test_and_change_bit(x, y) +#ifdef CONFIG_CPU_V8 + +#include <asm-generic/bitops/find.h> + +#else /* CONFIG_CPU_V8 */ + #ifndef __ARMEB__ /* * These are the little endian definitions. @@ -115,6 +121,8 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset); #endif /* __ARMEB__ */ +#endif /* CONFIG_CPU_V8 */ + #if defined (CONFIG_CPU_32) && defined(__LINUX_ARM_ARCH__) && (__LINUX_ARM_ARCH__ >= 5) static inline int constant_fls(int x) { diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index ef9cb98bf0..a0180f2df8 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -1,6 +1,26 @@ #ifndef __ASM_ARM_SYSTEM_H #define __ASM_ARM_SYSTEM_H +#include <linux/const.h> + +/* Common SCTLR_ELx flags. */ +#define SCTLR_ELx_DSSBS (_BITUL(44)) +#define SCTLR_ELx_ENIA (_BITUL(31)) +#define SCTLR_ELx_ENIB (_BITUL(30)) +#define SCTLR_ELx_ENDA (_BITUL(27)) +#define SCTLR_ELx_EE (_BITUL(25)) +#define SCTLR_ELx_IESB (_BITUL(21)) +#define SCTLR_ELx_WXN (_BITUL(19)) +#define SCTLR_ELx_ENDB (_BITUL(13)) +#define SCTLR_ELx_I (_BITUL(12)) +#define SCTLR_ELx_SA (_BITUL(3)) +#define SCTLR_ELx_C (_BITUL(2)) +#define SCTLR_ELx_A (_BITUL(1)) +#define SCTLR_ELx_M (_BITUL(0)) + +#define SCTLR_ELx_FLAGS (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | \ + SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_IESB) + #if __LINUX_ARM_ARCH__ >= 7 #define isb() __asm__ __volatile__ ("isb" : : : "memory") #ifdef CONFIG_CPU_64v8 diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c4e7500e8f..71d37cee90 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -454,6 +454,7 @@ config MACH_ZII_IMX8MQ_DEV select FIRMWARE_IMX8MQ_ATF select ARM_SMCCC select MCI_IMX_ESDHC_PBL + select MACH_ZII_COMMON config MACH_ZII_VF610_DEV bool "ZII VF610 Dev Family" diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index 01b4274ed3..e898be9ab5 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -117,7 +117,7 @@ static void imx6_setup_ipu_qos(void) uint32_t val; if (!cpu_mx6_is_mx6q() && !cpu_mx6_is_mx6d() && - !cpu_mx6_is_mx6dl() && cpu_mx6_is_mx6s()) + !cpu_mx6_is_mx6dl() && !cpu_mx6_is_mx6s()) return; val = readl(iomux + IOMUXC_GPR4); diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 665e8194ef..a7ea8f2d3b 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -94,7 +94,7 @@ int linux_tstc(int fd) return 0; } -int ctrlc(void) +int arch_ctrlc(void) { char chr; diff --git a/commands/Kconfig b/commands/Kconfig index 4f5d84ac18..039fd7d1ac 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1964,6 +1964,16 @@ config CMD_BAREBOX_UPDATE -y autom. use 'yes' when asking confirmations -f LEVEL set force level +config CMD_BLOBGEN + bool + select BLOBGEN + prompt "blobgen" + help + Provides the "blobgen" command. This command encrypts and decrypts + plaintext to/from blobs. This is done with hardware crypto engines, + so this command is only useful when you also enable a blobgen capable + driver. + config CMD_FIRMWARELOAD bool select FIRMWARE diff --git a/commands/Makefile b/commands/Makefile index 358671bb5b..e69fb5046f 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o obj-$(CONFIG_CMD_AUTOMOUNT) += automount.o obj-$(CONFIG_CMD_GLOBAL) += global.o obj-$(CONFIG_CMD_DMESG) += dmesg.o +obj-$(CONFIG_CMD_BLOBGEN) += blobgen.o obj-$(CONFIG_CMD_BASENAME) += basename.o obj-$(CONFIG_CMD_HAB) += hab.o obj-$(CONFIG_CMD_DIRNAME) += dirname.o diff --git a/commands/blobgen.c b/commands/blobgen.c new file mode 100644 index 0000000000..49107d037c --- /dev/null +++ b/commands/blobgen.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <common.h> +#include <command.h> +#include <getopt.h> +#include <blobgen.h> +#include <environment.h> + +static int do_blobgen(int argc, char *argv[]) +{ + bool do_encrypt = false, do_decrypt = false; + int opt; + const char *varname = NULL; + const char *modifier = NULL; + const char *blobdev = NULL; + struct blobgen *bg; + int plainsize; + int ret; + const char *message = NULL; + + while ((opt = getopt(argc, argv, "edm:V:b:")) > 0) { + switch (opt) { + case 'e': + do_encrypt = true; + break; + case 'd': + do_decrypt = true; + break; + case 'm': + modifier = optarg; + break; + case 'V': + varname = optarg; + break; + case 'b': + blobdev = optarg; + break; + } + } + + if (!varname) { + printf("varname not specified\n"); + return -EINVAL; + } + + if (!modifier) { + printf("Modifier not specified\n"); + return -EINVAL; + } + + bg = blobgen_get(blobdev); + if (!bg) { + printf("blobdev \"%s\" not found\n", blobdev); + return -ENOENT; + } + + if (do_encrypt && do_decrypt) { + printf("Both encrypt and decrypt given\n"); + return -EINVAL; + } + + if (!do_encrypt && !do_decrypt) { + printf("Specify either -e or -d option\n"); + return -EINVAL; + } + + if (argc > optind) { + message = argv[optind]; + } else { + printf("No message to %scrypt provided\n", + do_encrypt ? "en" : "de"); + return -EINVAL; + } + + if (do_encrypt) { + ret = blob_encrypt_to_env(bg, modifier, message, strlen(message), + varname); + if (ret) + return ret; + } + + if (do_decrypt) { + void *plain; + char *str; + + ret = blob_decrypt_from_base64(bg, modifier, message, &plain, + &plainsize); + if (ret) + return ret; + + str = malloc(plainsize + 1); + if (!str) + return -ENOMEM; + + memcpy(str, plain, plainsize); + str[plainsize] = 0; + + setenv(varname, str); + free(plain); + free(str); + } + + return 0; +} + +BAREBOX_CMD_HELP_START(blobgen) +BAREBOX_CMD_HELP_TEXT("This command utilizes hardware crypto engines to en/decrypt") +BAREBOX_CMD_HELP_TEXT("data blobs.") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-e\t", "encrypt") +BAREBOX_CMD_HELP_OPT("-d\t", "decrypt") +BAREBOX_CMD_HELP_OPT("-m <modifier>", "Set modifier") +BAREBOX_CMD_HELP_OPT("-V <varname>", "specify variable name to set with the result") +BAREBOX_CMD_HELP_OPT("-b <blobdev>", "specify blob device to use") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(blobgen) + .cmd = do_blobgen, + BAREBOX_CMD_DESC("en/decrypt blobs") + BAREBOX_CMD_OPTS("[-edmVb] <plaintext/ciphertext>") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_blobgen_help) +BAREBOX_CMD_END diff --git a/commands/timeout.c b/commands/timeout.c index d197cedd8b..db88900287 100644 --- a/commands/timeout.c +++ b/commands/timeout.c @@ -61,7 +61,7 @@ static int do_timeout(int argc, char *argv[]) return COMMAND_ERROR_USAGE; timeout = simple_strtoul(argv[optind], NULL, 0); - ret = console_countdown(timeout, flags, str); + ret = console_countdown(timeout, flags, NULL, str); if (varname && str[0]) setenv(varname, str); diff --git a/common/console.c b/common/console.c index 47ccf2e54d..406722a1da 100644 --- a/common/console.c +++ b/common/console.c @@ -574,18 +574,60 @@ void console_flush(void) } EXPORT_SYMBOL(console_flush); -#ifndef ARCH_HAS_CTRLC +static int ctrlc_abort; +static int ctrlc_allowed; + +void ctrlc_handled(void) +{ + ctrlc_abort = 0; +} + /* test if ctrl-c was pressed */ -int ctrlc (void) +int ctrlc(void) { + int ret = 0; + + if (!ctrlc_allowed) + return 0; + + if (ctrlc_abort) + return 1; + poller_call(); +#ifdef ARCH_HAS_CTRLC + ret = arch_ctrlc(); +#else if (tstc() && getchar() == 3) - return 1; - return 0; + ret = 1; +#endif + + if (ret) + ctrlc_abort = 1; + + return ret; } EXPORT_SYMBOL(ctrlc); -#endif /* ARCH_HAS_CTRC */ + +static int console_ctrlc_init(void) +{ + globalvar_add_simple_bool("console.ctrlc_allowed", &ctrlc_allowed); + return 0; +} +device_initcall(console_ctrlc_init); + +void console_ctrlc_allow(void) +{ + ctrlc_allowed = 1; +} + +void console_ctrlc_forbid(void) +{ + ctrlc_allowed = 0; +} + +BAREBOX_MAGICVAR_NAMED(global_console_ctrlc_allowed, global.console.ctrlc_allowed, + "If true, scripts can be aborted with ctrl-c"); BAREBOX_MAGICVAR_NAMED(global_linux_bootargs_console, global.linux.bootargs.console, "console= argument for Linux from the stdout-path property in /chosen node"); diff --git a/common/console_countdown.c b/common/console_countdown.c index 36da1ce577..8d09894c30 100644 --- a/common/console_countdown.c +++ b/common/console_countdown.c @@ -30,7 +30,22 @@ void console_countdown_abort(void) console_countdown_timeout_abort = true; } -int console_countdown(int timeout_s, unsigned flags, char *out_key) +static int key_in_list(char key, const char *keys) +{ + if (!keys) + return false; + + while (*keys) { + if (key == *keys) + return true; + keys++; + } + + return false; +} + +int console_countdown(int timeout_s, unsigned flags, const char *keys, + char *out_key) { uint64_t start, second; int countdown, ret = -EINTR; @@ -48,6 +63,8 @@ int console_countdown(int timeout_s, unsigned flags, char *out_key) if (tstc()) { key = getchar(); if (key >= 0) { + if (key_in_list(key, keys)) + goto out; if (flags & CONSOLE_COUNTDOWN_ANYKEY) goto out; if (flags & CONSOLE_COUNTDOWN_RETURN && key == '\n') diff --git a/common/hush.c b/common/hush.c index d2f9cc70f5..dab9b04081 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1734,7 +1734,7 @@ static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int fla return 1; } b_free(&temp); - } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ + } while (!ctrlc() && rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ return code; } @@ -1932,6 +1932,7 @@ int run_shell(void) login(); do { + ctrlc_handled(); setup_file_in_str(&input); rcode = parse_stream_outer(&ctx, &input, FLAG_PARSE_SEMICOLON); if (rcode < -1) { diff --git a/common/parser.c b/common/parser.c index 397d268da1..fb9ef42e7f 100644 --- a/common/parser.c +++ b/common/parser.c @@ -283,6 +283,7 @@ int run_shell(void) /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } + ctrlc_handled(); } } return 0; diff --git a/common/startup.c b/common/startup.c index 28edee4fce..9fac0eabbd 100644 --- a/common/startup.c +++ b/common/startup.c @@ -42,6 +42,9 @@ #include <asm/sections.h> #include <uncompress.h> #include <globalvar.h> +#include <console_countdown.h> +#include <environment.h> +#include <linux/ctype.h> extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], __barebox_initcalls_end[]; @@ -143,16 +146,172 @@ static int load_environment(void) environment_initcall(load_environment); #endif +static int global_autoboot_abort_key; +static const char * const global_autoboot_abort_keys[] = { + "any", + "ctrl-c", +}; +static int global_autoboot_timeout = 3; +static char *global_boot_default; +static char *global_editcmd; +static char *global_linux_bootargs_base; +static char *global_linux_bootargs_console; +static char *global_linux_bootargs_dyn_ip; +static char *global_linux_bootargs_dyn_root; +static char *global_user; + +static bool test_abort(void) +{ + bool do_abort = false; + int c, ret; + char key; + + while (tstc()) { + c = getchar(); + if (tolower(c) == 'q' || c == 3) + do_abort = true; + } + + if (!do_abort) + return false; + + printf("Abort init sequence? (y/n)\n" + "Will continue with init sequence in:"); + + ret = console_countdown(5, CONSOLE_COUNTDOWN_EXTERN, "yYnN", &key); + if (!ret) + return false; + + if (tolower(key) == 'y') + return true; + + return false; +} + +static int run_init(void) +{ + DIR *dir; + struct dirent *d; + const char *initfile = "/env/bin/init"; + const char *initdir = "/env/init"; + const char *menufile = "/env/menu/mainmenu"; + struct stat s; + unsigned flags = CONSOLE_COUNTDOWN_EXTERN; + unsigned char outkey; + int ret; + bool menu_exists; + bool env_bin_init_exists; + char *abortkeys = NULL; + + setenv("PATH", "/env/bin"); + + /* Run legacy /env/bin/init if it exists */ + env_bin_init_exists = stat(initfile, &s) == 0; + if (env_bin_init_exists) { + pr_info("running %s...\n", initfile); + run_command(initfile); + return 0; + } + + global_editcmd = xstrdup("sedit"); + global_user = xstrdup("none"); + globalvar_add_simple_string("user", &global_user); + global_boot_default = xstrdup("net"); + + globalvar_add_simple_enum("autoboot_abort_key", + &global_autoboot_abort_key, + global_autoboot_abort_keys, + ARRAY_SIZE(global_autoboot_abort_keys)); + globalvar_add_simple_int("autoboot_timeout", + &global_autoboot_timeout, "%u"); + globalvar_add_simple_string("boot.default", &global_boot_default); + globalvar_add_simple_string("editcmd", &global_editcmd); + globalvar_add_simple_string("linux.bootargs.base", + &global_linux_bootargs_base); + globalvar_add_simple_string("linux.bootargs.console", + &global_linux_bootargs_console); + globalvar_add_simple_string("linux.bootargs.dyn.ip", + &global_linux_bootargs_dyn_ip); + globalvar_add_simple_string("linux.bootargs.dyn.root", + &global_linux_bootargs_dyn_root); + + /* Unblank console cursor */ + printf("\e[?25h"); + + if (test_abort()) { + pr_info("Init sequence aborted\n"); + return -EINTR; + } + + /* Run scripts in /env/init/ */ + dir = opendir(initdir); + if (dir) { + char *scr; + + while ((d = readdir(dir))) { + if (*d->d_name == '.') + continue; + + pr_debug("Executing '%s/%s'...\n", initdir, d->d_name); + scr = basprintf("source %s/%s", initdir, d->d_name); + run_command(scr); + free(scr); + } + + closedir(dir); + } + + menu_exists = stat(menufile, &s) == 0; + + if (menu_exists) { + printf("\nHit m for menu or %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + abortkeys = "m"; + } else { + printf("\nHit %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + } + + switch (global_autoboot_abort_key) { + case 0: + flags |= CONSOLE_COUNTDOWN_ANYKEY; + break; + case 1: + flags |= CONSOLE_COUNTDOWN_CTRLC; + break; + default: + break; + } + + ret = console_countdown(global_autoboot_timeout, flags, abortkeys, + &outkey); + + if (ret == 0) + run_command("boot"); + + console_ctrlc_allow(); + + if (menu_exists) { + if (outkey == 'm') + run_command(menufile); + + printf("Enter 'exit' to get back to the menu\n"); + run_shell(); + run_command(menufile); + } + + return 0; +} + int (*barebox_main)(void); void __noreturn start_barebox(void) { initcall_t *initcall; int result; - struct stat s; - if (!IS_ENABLED(CONFIG_SHELL_NONE)) - barebox_main = run_shell; + if (!IS_ENABLED(CONFIG_SHELL_NONE) && IS_ENABLED(CONFIG_COMMAND_SUPPORT)) + barebox_main = run_init; for (initcall = __barebox_initcalls_start; initcall < __barebox_initcalls_end; initcall++) { @@ -165,25 +324,16 @@ void __noreturn start_barebox(void) pr_debug("initcalls done\n"); - if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { - pr_info("running /env/bin/init...\n"); - - if (!stat("/env/bin/init", &s)) - run_command("source /env/bin/init"); - else - pr_err("/env/bin/init not found\n"); - } + if (barebox_main) + barebox_main(); - if (!barebox_main) { - pr_err("No main function! aborting.\n"); + if (IS_ENABLED(CONFIG_SHELL_NONE)) { + pr_err("Nothing left to do\n"); hang(); + } else { + while (1) + run_shell(); } - - /* main_loop() can return to retry autoboot, if so just run it again. */ - for (;;) - barebox_main(); - - /* NOTREACHED - no way out of command loop except booting */ } void __noreturn hang (void) diff --git a/defaultenv/defaultenv-2-base/bin/init b/defaultenv/defaultenv-2-base/bin/init deleted file mode 100644 index 8d02e3d3ab..0000000000 --- a/defaultenv/defaultenv-2-base/bin/init +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -export PATH=/env/bin - -global hostname -global user -global autoboot_timeout -global autoboot_abort_key -global boot.default -global linux.bootargs.base -global linux.bootargs.console -#linux.bootargs.dyn.* will be cleared at the beginning of boot -global linux.bootargs.dyn.ip -global linux.bootargs.dyn.root -global editcmd - -[ -z "${global.hostname}" ] && global.hostname=generic -[ -z "${global.user}" ] && global.user=none -magicvar -a global.user "username (used in network filenames)" -[ -z "${global.autoboot_timeout}" ] && global.autoboot_timeout=3 -magicvar -a global.autoboot_timeout "timeout in seconds before automatic booting" -[ -z "${global.autoboot_abort_key}" ] && global.autoboot_abort_key=any -magicvar -a global.autoboot_abort_key "key to abort automatic booting (valid options: any, ctrl-c)" -[ -z "${global.boot.default}" ] && global.boot.default=net -[ -z "${global.editcmd}" ] && global.editcmd=sedit - -[ -e /env/config-board ] && /env/config-board -/env/config - -# allow to stop the boot before execute the /env/init/* -# but without waiting -timeout -s -a -v key 0 -autoboot="$?" - -echo -e -n "\e[?25h" -if [ "${key}" = "q" ]; then - exit -fi - -for i in /env/init/*; do - . $i -done - -if [ "${global.autoboot_abort_key}" = "ctrl-c" ]; then - abort_string="ctrl-c" - abort_args="-c" -else - abort_string="any key" - abort_args="-a" -fi - -if [ -e /env/menu ]; then - echo -e -n "\nHit m for menu or $abort_string to stop autoboot: " -else - echo -e -n "\nHit $abort_string to stop autoboot: " -fi - -if [ "$autoboot" = 0 ]; then - timeout $abort_args $global.autoboot_timeout -v key - autoboot="$?" -fi - -if [ "${key}" = "q" ]; then - exit -fi - -if [ "$autoboot" = 0 ]; then - boot -fi - -if [ -e /env/menu ]; then - if [ "${key}" != "m" ]; then - echo -e "\ntype exit to get to the menu" - sh - fi - /env/menu/mainmenu -fi diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index b2709f00f8..77d3782bde 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -5,5 +5,6 @@ menuconfig CRYPTO_HW if CRYPTO_HW source "drivers/crypto/caam/Kconfig" +source "drivers/crypto/imx-scc/Kconfig" endif diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 67f968f76c..1999929bc2 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += imx-scc/ diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 7bd6f3e23c..933b9c0592 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += ctrl.o error.o jr.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG) += caamrng.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_SELF_TEST) += rng_self_test.o +obj-$(CONFIG_BLOBGEN) += caam-blobgen.o diff --git a/drivers/crypto/caam/caam-blobgen.c b/drivers/crypto/caam/caam-blobgen.c new file mode 100644 index 0000000000..acbe5a110d --- /dev/null +++ b/drivers/crypto/caam/caam-blobgen.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <common.h> +#include <asm/io.h> +#include <base64.h> +#include <blobgen.h> +#include <crypto.h> +#include <dma.h> +#include <driver.h> +#include <init.h> +#include <fs.h> +#include <fcntl.h> +#include "intern.h" +#include "desc.h" +#include "desc_constr.h" +#include "error.h" +#include "jr.h" + +/* + * Upon completion, desc points to a buffer containing a CAAM job + * descriptor which encapsulates data into an externally-storable + * blob. + */ +#define INITIAL_DESCSZ 16 +/* 32 bytes key blob + 16 bytes HMAC identifier */ +#define BLOB_OVERHEAD (32 + 16) +#define KEYMOD_LENGTH 16 +#define RED_BLOB_LENGTH 64 +#define MAX_BLOB_LEN 4096 +#define DESC_LEN 64 + +struct blob_job_result { + int err; +}; + +struct blob_priv { + struct blobgen bg; + u32 desc[DESC_LEN]; + dma_addr_t dma_modifier; + dma_addr_t dma_plaintext; + dma_addr_t dma_ciphertext; +}; + +static struct blob_priv *to_blob_priv(struct blobgen *bg) +{ + return container_of(bg, struct blob_priv, bg); +} + +static void jr_jobdesc_blob_decap(struct blob_priv *ctx, u8 modlen, u16 input_size) +{ + u32 *desc = ctx->desc; + u16 in_sz; + u16 out_sz; + + in_sz = input_size; + out_sz = input_size - BLOB_OVERHEAD; + + init_job_desc(desc, 0); + /* + * The key modifier can be used to differentiate specific data. + * Or to prevent replay attacks. + */ + append_key(desc, ctx->dma_modifier, modlen, CLASS_2); + append_seq_in_ptr(desc, ctx->dma_ciphertext, in_sz, 0); + append_seq_out_ptr(desc, ctx->dma_plaintext, out_sz, 0); + append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB); +} + +static void jr_jobdesc_blob_encap(struct blob_priv *ctx, u8 modlen, u16 input_size) +{ + u32 *desc = ctx->desc; + u16 in_sz; + u16 out_sz; + + in_sz = input_size; + out_sz = input_size + BLOB_OVERHEAD; + + init_job_desc(desc, 0); + /* + * The key modifier can be used to differentiate specific data. + * Or to prevent replay attacks. + */ + append_key(desc, ctx->dma_modifier, modlen, CLASS_2); + append_seq_in_ptr(desc, ctx->dma_plaintext, in_sz, 0); + append_seq_out_ptr(desc, ctx->dma_ciphertext, out_sz, 0); + append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB); +} + +static void blob_job_done(struct device_d *dev, u32 *desc, u32 err, void *arg) +{ + struct blob_job_result *res = arg; + + if (!res) + return; + + if (err) + caam_jr_strstatus(dev, err); + + res->err = err; +} + +static int caam_blob_decrypt(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize) +{ + struct blob_priv *ctx = to_blob_priv(bg); + struct device_d *jrdev = bg->dev.parent; + struct blob_job_result testres; + int modifier_len = strlen(modifier); + u32 *desc = ctx->desc; + int ret; + + if (blobsize <= BLOB_OVERHEAD) + return -EINVAL; + + *plainsize = blobsize - BLOB_OVERHEAD; + + *plain = dma_alloc(*plainsize); + if (!*plain) + return -ENOMEM; + + memset(desc, 0, DESC_LEN); + + ctx->dma_modifier = (dma_addr_t)modifier; + ctx->dma_plaintext = (dma_addr_t)*plain; + ctx->dma_ciphertext = (dma_addr_t)blob; + + jr_jobdesc_blob_decap(ctx, modifier_len, blobsize); + + dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc), + DMA_TO_DEVICE); + + dma_sync_single_for_device((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)*plain, *plainsize, + DMA_FROM_DEVICE); + dma_sync_single_for_device((unsigned long)blob, blobsize, + DMA_TO_DEVICE); + + testres.err = 0; + + ret = caam_jr_enqueue(jrdev, desc, blob_job_done, &testres); + if (ret) + dev_err(jrdev, "decryption error\n"); + + ret = testres.err; + + dma_sync_single_for_cpu((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)*plain, *plainsize, + DMA_FROM_DEVICE); + dma_sync_single_for_cpu((unsigned long)blob, blobsize, + DMA_TO_DEVICE); + + return ret; +} + +static int caam_blob_encrypt(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize) +{ + struct blob_priv *ctx = to_blob_priv(bg); + struct device_d *jrdev = bg->dev.parent; + struct blob_job_result testres; + int modifier_len = strlen(modifier); + u32 *desc = ctx->desc; + int ret; + + *blobsize = plainsize + BLOB_OVERHEAD; + + memset(desc, 0, DESC_LEN); + + ctx->dma_modifier = (dma_addr_t)modifier; + ctx->dma_plaintext = (dma_addr_t)plain; + ctx->dma_ciphertext = (dma_addr_t)blob; + + jr_jobdesc_blob_encap(ctx, modifier_len, plainsize); + + dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc), + DMA_TO_DEVICE); + + dma_sync_single_for_device((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)plain, plainsize, + DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)blob, *blobsize, + DMA_FROM_DEVICE); + + testres.err = 0; + + ret = caam_jr_enqueue(jrdev, desc, blob_job_done, &testres); + if (ret) + dev_err(jrdev, "encryption error\n"); + + ret = testres.err; + + dma_sync_single_for_cpu((unsigned long)modifier, modifier_len, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)plain, plainsize, + DMA_TO_DEVICE); + dma_sync_single_for_cpu((unsigned long)blob, *blobsize, + DMA_FROM_DEVICE); + + return ret; +} + +int caam_blob_gen_probe(struct device_d *dev, struct device_d *jrdev) +{ + struct blob_priv *ctx; + struct blobgen *bg; + int ret; + + ctx = xzalloc(sizeof(*ctx)); + bg = &ctx->bg; + bg->max_payload_size = MAX_BLOB_LEN - BLOB_OVERHEAD; + bg->encrypt = caam_blob_encrypt; + bg->decrypt = caam_blob_decrypt; + + ret = blob_gen_register(jrdev, bg); + if (ret) + free(ctx); + + return ret; +} diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 4fe3eea3e6..06b075e74a 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -654,6 +654,15 @@ static int caam_probe(struct device_d *dev) } } + if (IS_ENABLED(CONFIG_BLOBGEN)) { + ret = caam_blob_gen_probe(dev, ctrlpriv->jrpdev[0]); + if (ret) { + dev_err(dev, "failed to instantiate blobgen device"); + caam_remove(dev); + return ret; + } + } + /* NOTE: RTIC detection ought to go here, around Si time */ caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 | (u64)rd_reg32(&ctrl->perfmon.caam_id_ls); diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index fe19a2c8d2..6dfcea26ac 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -93,5 +93,6 @@ void caam_jr_algapi_init(struct device *dev); void caam_jr_algapi_remove(struct device *dev); int caam_rng_probe(struct device_d *dev, struct device_d *jrdev); +int caam_blob_gen_probe(struct device_d *dev, struct device_d *jrdev); int caam_jr_probe(struct device_d *dev); #endif /* INTERN_H */ diff --git a/drivers/crypto/caam/rng_self_test.c b/drivers/crypto/caam/rng_self_test.c index aab4fa2e47..7816cd152c 100644 --- a/drivers/crypto/caam/rng_self_test.c +++ b/drivers/crypto/caam/rng_self_test.c @@ -51,6 +51,7 @@ #include "error.h" #include "regs.h" #include "jr.h" +#include "rng_self_test.h" static const u32 rng_dsc1[] = { 0xb0800036, 0x04800010, 0x3c85a15b, 0x50a9d0b1, diff --git a/drivers/crypto/imx-scc/Kconfig b/drivers/crypto/imx-scc/Kconfig new file mode 100644 index 0000000000..531304f432 --- /dev/null +++ b/drivers/crypto/imx-scc/Kconfig @@ -0,0 +1,14 @@ +config CRYPTO_DEV_MXC_SCC + tristate "Support for Freescale Security Controller (SCC)" + depends on ARCH_IMX25 && OFTREE + select CRYPTO_BLKCIPHER + select CRYPTO_DES + help + This option enables support for the Security Controller (SCC) + found in Freescale i.MX25 chips. + +config CRYPTO_DEV_MXC_SCC_BLOB_GEN + tristate "Support for SCC blob gen" + depends on ARCH_IMX25 + select BLOBGEN + select CRYPTO_DEV_MXC_SCC diff --git a/drivers/crypto/imx-scc/Makefile b/drivers/crypto/imx-scc/Makefile new file mode 100644 index 0000000000..c30fd1e12d --- /dev/null +++ b/drivers/crypto/imx-scc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += scc.o +obj-$(CONFIG_CRYPTO_DEV_MXC_SCC_BLOB_GEN) += scc-blobgen.o diff --git a/drivers/crypto/imx-scc/scc-blobgen.c b/drivers/crypto/imx-scc/scc-blobgen.c new file mode 100644 index 0000000000..e1a1372420 --- /dev/null +++ b/drivers/crypto/imx-scc/scc-blobgen.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <common.h> +#include <dma.h> +#include <digest.h> +#include <driver.h> +#include <init.h> +#include <blobgen.h> +#include <stdlib.h> +#include <crypto.h> +#include <crypto/sha.h> + +#include "scc.h" + +#define MAX_IVLEN BLOCKSIZE_BYTES + +static struct digest *sha256; + +static int sha256sum(uint8_t *src, uint8_t *dst, unsigned int size) +{ + if (!sha256) + sha256 = digest_alloc("sha256"); + + if (!sha256) { + pr_err("Unable to allocate sha256 digest\n"); + return -EINVAL; + } + + return digest_digest(sha256, src, size, dst); +} + +static int imx_scc_blob_encrypt(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize) +{ + char *s; + int bufsiz; + struct ablkcipher_request req = {}; + uint8_t iv[MAX_IVLEN]; + uint8_t hash[SHA256_DIGEST_SIZE]; + int ret; + + bufsiz = ALIGN(plainsize + KEYMOD_LENGTH, 8); + + s = malloc(bufsiz + SHA256_DIGEST_SIZE); + if (!s) + return -ENOMEM; + + memset(s, 0, bufsiz); + + strncpy(s, modifier, KEYMOD_LENGTH); + memcpy(s + KEYMOD_LENGTH, plain, plainsize); + + ret = sha256sum(s, hash, bufsiz); + if (ret) + goto out; + + memcpy(s + bufsiz, hash, SHA256_DIGEST_SIZE); + + bufsiz += SHA256_DIGEST_SIZE; + + req.info = iv; + req.src = s; + req.dst = blob; + req.nbytes = bufsiz; + + get_random_bytes(req.info, MAX_IVLEN); + + ret = imx_scc_cbc_des_encrypt(&req); + if (ret) + goto out; + + memcpy(blob + bufsiz, req.info, MAX_IVLEN); + *blobsize = bufsiz + MAX_IVLEN; + +out: + free(s); + + return ret; +} + +static int imx_scc_blob_decrypt(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize) +{ + struct ablkcipher_request req = {}; + uint8_t iv[MAX_IVLEN]; + uint8_t hash[SHA256_DIGEST_SIZE]; + int ret; + uint8_t *data; + int ciphersize = blobsize - MAX_IVLEN; + + if (blobsize <= MAX_IVLEN + SHA256_DIGEST_SIZE + KEYMOD_LENGTH) + return -EINVAL; + + data = malloc(ciphersize); + if (!data) + return -ENOMEM; + + req.info = iv; + req.nbytes = ciphersize; + req.src = (void *)blob; + req.dst = data; + + memcpy(req.info, blob + req.nbytes, MAX_IVLEN); + + ret = imx_scc_cbc_des_decrypt(&req); + if (ret) + goto out; + + ret = sha256sum(data, hash, ciphersize - SHA256_DIGEST_SIZE); + if (ret) + goto out; + + if (memcmp(data + ciphersize - SHA256_DIGEST_SIZE, hash, + SHA256_DIGEST_SIZE)) { + pr_err("%s: Corrupted SHA256 digest. Can't continue.\n", + bg->dev.name); + pr_err("%s: Calculated hash:\n", bg->dev.name); + memory_display(hash, 0, SHA256_DIGEST_SIZE, 1, 0); + pr_err("%s: Received hash:\n", bg->dev.name); + memory_display(data + ciphersize - SHA256_DIGEST_SIZE, + 0, SHA256_DIGEST_SIZE, 1, 0); + + ret = -EILSEQ; + goto out; + } + + *plainsize = ciphersize - SHA256_DIGEST_SIZE - KEYMOD_LENGTH; + *plain = xmemdup(data + KEYMOD_LENGTH, *plainsize); +out: + free(data); + + return ret; +} + +int imx_scc_blob_gen_probe(struct device_d *dev) +{ + struct blobgen *bg; + int ret; + + bg = xzalloc(sizeof(*bg)); + + bg->max_payload_size = MAX_BLOB_LEN - MAX_IVLEN - + SHA256_DIGEST_SIZE - KEYMOD_LENGTH; + bg->encrypt = imx_scc_blob_encrypt; + bg->decrypt = imx_scc_blob_decrypt; + + ret = blob_gen_register(dev, bg); + if (ret) + free(bg); + + return ret; +} diff --git a/drivers/crypto/imx-scc/scc.c b/drivers/crypto/imx-scc/scc.c new file mode 100644 index 0000000000..5a35c3506d --- /dev/null +++ b/drivers/crypto/imx-scc/scc.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * The driver is based on information gathered from + * drivers/mxc/security/imx_scc.c which can be found in + * the Freescale linux-2.6-imx.git in the imx_2.6.35_maintain branch. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * 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. + * + */ +#include <common.h> +#include <clock.h> +#include <driver.h> +#include <init.h> +#include <io.h> +#include <crypto.h> +#include <linux/barebox-wrapper.h> +#include <linux/clk.h> +#include <crypto/des.h> + +#include "scc.h" + +/* Secure Memory (SCM) registers */ +#define SCC_SCM_RED_START 0x0000 +#define SCC_SCM_BLACK_START 0x0004 +#define SCC_SCM_LENGTH 0x0008 +#define SCC_SCM_CTRL 0x000C +#define SCC_SCM_STATUS 0x0010 +#define SCC_SCM_ERROR_STATUS 0x0014 +#define SCC_SCM_INTR_CTRL 0x0018 +#define SCC_SCM_CFG 0x001C +#define SCC_SCM_INIT_VECTOR_0 0x0020 +#define SCC_SCM_INIT_VECTOR_1 0x0024 +#define SCC_SCM_RED_MEMORY 0x0400 +#define SCC_SCM_BLACK_MEMORY 0x0800 + +/* Security Monitor (SMN) Registers */ +#define SCC_SMN_STATUS 0x1000 +#define SCC_SMN_COMMAND 0x1004 +#define SCC_SMN_SEQ_START 0x1008 +#define SCC_SMN_SEQ_END 0x100C +#define SCC_SMN_SEQ_CHECK 0x1010 +#define SCC_SMN_BIT_COUNT 0x1014 +#define SCC_SMN_BITBANK_INC_SIZE 0x1018 +#define SCC_SMN_BITBANK_DECREMENT 0x101C +#define SCC_SMN_COMPARE_SIZE 0x1020 +#define SCC_SMN_PLAINTEXT_CHECK 0x1024 +#define SCC_SMN_CIPHERTEXT_CHECK 0x1028 +#define SCC_SMN_TIMER_IV 0x102C +#define SCC_SMN_TIMER_CONTROL 0x1030 +#define SCC_SMN_DEBUG_DETECT_STAT 0x1034 +#define SCC_SMN_TIMER 0x1038 + +#define SCC_SCM_CTRL_START_CIPHER BIT(2) +#define SCC_SCM_CTRL_CBC_MODE BIT(1) +#define SCC_SCM_CTRL_DECRYPT_MODE BIT(0) + +#define SCC_SCM_STATUS_LEN_ERR BIT(12) +#define SCC_SCM_STATUS_SMN_UNBLOCKED BIT(11) +#define SCC_SCM_STATUS_CIPHERING_DONE BIT(10) +#define SCC_SCM_STATUS_ZEROIZING_DONE BIT(9) +#define SCC_SCM_STATUS_INTR_STATUS BIT(8) +#define SCC_SCM_STATUS_SEC_KEY BIT(7) +#define SCC_SCM_STATUS_INTERNAL_ERR BIT(6) +#define SCC_SCM_STATUS_BAD_SEC_KEY BIT(5) +#define SCC_SCM_STATUS_ZEROIZE_FAIL BIT(4) +#define SCC_SCM_STATUS_SMN_BLOCKED BIT(3) +#define SCC_SCM_STATUS_CIPHERING BIT(2) +#define SCC_SCM_STATUS_ZEROIZING BIT(1) +#define SCC_SCM_STATUS_BUSY BIT(0) + +#define SCC_SMN_STATUS_STATE_MASK 0x0000001F +#define SCC_SMN_STATE_START 0x0 +/* The SMN is zeroizing its RAM during reset */ +#define SCC_SMN_STATE_ZEROIZE_RAM 0x5 +/* SMN has passed internal checks */ +#define SCC_SMN_STATE_HEALTH_CHECK 0x6 +/* Fatal Security Violation. SMN is locked, SCM is inoperative. */ +#define SCC_SMN_STATE_FAIL 0x9 +/* SCC is in secure state. SCM is using secret key. */ +#define SCC_SMN_STATE_SECURE 0xA +/* SCC is not secure. SCM is using default key. */ +#define SCC_SMN_STATE_NON_SECURE 0xC + +#define SCC_SCM_INTR_CTRL_ZEROIZE_MEM BIT(2) +#define SCC_SCM_INTR_CTRL_CLR_INTR BIT(1) +#define SCC_SCM_INTR_CTRL_MASK_INTR BIT(0) + +/* Size, in blocks, of Red memory. */ +#define SCC_SCM_CFG_BLACK_SIZE_MASK 0x07fe0000 +#define SCC_SCM_CFG_BLACK_SIZE_SHIFT 17 +/* Size, in blocks, of Black memory. */ +#define SCC_SCM_CFG_RED_SIZE_MASK 0x0001ff80 +#define SCC_SCM_CFG_RED_SIZE_SHIFT 7 +/* Number of bytes per block. */ +#define SCC_SCM_CFG_BLOCK_SIZE_MASK 0x0000007f + +#define SCC_SMN_COMMAND_TAMPER_LOCK BIT(4) +#define SCC_SMN_COMMAND_CLR_INTR BIT(3) +#define SCC_SMN_COMMAND_CLR_BIT_BANK BIT(2) +#define SCC_SMN_COMMAND_EN_INTR BIT(1) +#define SCC_SMN_COMMAND_SET_SOFTWARE_ALARM BIT(0) + +#define SCC_KEY_SLOTS 20 +#define SCC_MAX_KEY_SIZE 32 +#define SCC_KEY_SLOT_SIZE 32 + +#define SCC_CRC_CCITT_START 0xFFFF + +/* + * Offset into each RAM of the base of the area which is not + * used for Stored Keys. + */ +#define SCC_NON_RESERVED_OFFSET (SCC_KEY_SLOTS * SCC_KEY_SLOT_SIZE) + +/* Fixed padding for appending to plaintext to fill out a block */ +static char scc_block_padding[8] = { 0x80, 0, 0, 0, 0, 0, 0, 0 }; + +struct imx_scc { + struct device_d *dev; + void __iomem *base; + struct clk *clk; + struct ablkcipher_request *req; + unsigned int block_size_bytes; + unsigned int black_ram_size_blocks; + unsigned int memory_size_bytes; + unsigned int bytes_remaining; + + void __iomem *red_memory; + void __iomem *black_memory; +}; + +struct imx_scc_ctx { + struct imx_scc *scc; + unsigned int offset; + unsigned int size; + unsigned int ctrl; +}; + +static struct imx_scc *scc_dev; + +static int imx_scc_get_data(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + struct imx_scc *scc = ctx->scc; + void __iomem *from; + + if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) + from = scc->red_memory; + else + from = scc->black_memory; + + memcpy(ablkreq->dst, from + ctx->offset, ctx->size); + + pr_debug("GET_DATA:\n"); + pr_memory_display(MSG_DEBUG, from, 0, ctx->size, 0x40 >> 3, 0); + + ctx->offset += ctx->size; + + if (ctx->offset < ablkreq->nbytes) + return -EINPROGRESS; + + return 0; +} + +static int imx_scc_ablkcipher_req_init(struct ablkcipher_request *req, + struct imx_scc_ctx *ctx) +{ + ctx->size = 0; + ctx->offset = 0; + + return 0; +} + +static int imx_scc_put_data(struct imx_scc_ctx *ctx, + struct ablkcipher_request *req) +{ + u8 padding_buffer[sizeof(u16) + sizeof(scc_block_padding)]; + size_t len = min(req->nbytes - ctx->offset, ctx->scc->bytes_remaining); + unsigned int padding_byte_count = 0; + struct imx_scc *scc = ctx->scc; + void __iomem *to; + + if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) + to = scc->black_memory; + else + to = scc->red_memory; + + if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE) { + dev_dbg(scc->dev, "set IV@0x%p\n", scc->base + SCC_SCM_INIT_VECTOR_0); + memcpy(scc->base + SCC_SCM_INIT_VECTOR_0, req->info, + scc->block_size_bytes); + } + + memcpy(to, req->src + ctx->offset, len); + + ctx->size = len; + + scc->bytes_remaining -= len; + + padding_byte_count = ((len + scc->block_size_bytes - 1) & + ~(scc->block_size_bytes-1)) - len; + + if (padding_byte_count) { + memcpy(padding_buffer, scc_block_padding, padding_byte_count); + memcpy(to + len, padding_buffer, padding_byte_count); + ctx->size += padding_byte_count; + } + + dev_dbg(scc->dev, "copied %d bytes to 0x%p\n", ctx->size, to); + pr_debug("IV:\n"); + pr_memory_display(MSG_DEBUG, scc->base + SCC_SCM_INIT_VECTOR_0, 0, + scc->block_size_bytes, + 0x40 >> 3, 0); + pr_debug("DATA:\n"); + pr_memory_display(MSG_DEBUG, to, 0, ctx->size, 0x40 >> 3, 0); + + return 0; +} + +static int imx_scc_ablkcipher_next(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + struct imx_scc *scc = ctx->scc; + int err; + + writel(0, scc->base + SCC_SCM_ERROR_STATUS); + + err = imx_scc_put_data(ctx, ablkreq); + if (err) + return err; + + dev_dbg(scc->dev, "Start encryption (0x%p/0x%p)\n", + (void *)readl(scc->base + SCC_SCM_RED_START), + (void *)readl(scc->base + SCC_SCM_BLACK_START)); + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR, + scc->base + SCC_SCM_INTR_CTRL); + + writel((ctx->size / ctx->scc->block_size_bytes) - 1, + scc->base + SCC_SCM_LENGTH); + + dev_dbg(scc->dev, "Process %d block(s) in 0x%p\n", + ctx->size / ctx->scc->block_size_bytes, + (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) ? scc->black_memory : + scc->red_memory); + + writel(ctx->ctrl, scc->base + SCC_SCM_CTRL); + + return 0; +} + +static int imx_scc_int(struct imx_scc_ctx *ctx) +{ + struct ablkcipher_request *ablkreq; + struct imx_scc *scc = ctx->scc; + uint64_t start; + + start = get_time_ns(); + while (readl(scc->base + SCC_SCM_STATUS) & SCC_SCM_STATUS_BUSY) { + if (is_timeout(start, 100 * MSECOND)) { + dev_err(scc->dev, "timeout waiting for interrupt\n"); + return -ETIMEDOUT; + } + } + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR, scc->base + SCC_SCM_INTR_CTRL); + + ablkreq = scc->req; + + if (ablkreq) + return imx_scc_get_data(ctx, ablkreq); + + return 0; +} + +static int imx_scc_process_req(struct imx_scc_ctx *ctx, + struct ablkcipher_request *ablkreq) +{ + int ret = -EINPROGRESS; + + ctx->scc->req = ablkreq; + + while (ret == -EINPROGRESS) { + ret = imx_scc_ablkcipher_next(ctx, ablkreq); + if (ret) + break; + ret = imx_scc_int(ctx); + } + + ctx->scc->req = NULL; + ctx->scc->bytes_remaining = ctx->scc->memory_size_bytes; + + return 0; +} + +static int imx_scc_des3_op(struct imx_scc_ctx *ctx, + struct ablkcipher_request *req) +{ + int err; + + err = imx_scc_ablkcipher_req_init(req, ctx); + if (err) + return err; + + return imx_scc_process_req(ctx, req); +} + +int imx_scc_cbc_des_encrypt(struct ablkcipher_request *req) +{ + struct imx_scc_ctx *ctx; + + ctx = xzalloc(sizeof(*ctx)); + ctx->scc = scc_dev; + + ctx->ctrl = SCC_SCM_CTRL_START_CIPHER; + ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE; + + return imx_scc_des3_op(ctx, req); +} + +int imx_scc_cbc_des_decrypt(struct ablkcipher_request *req) +{ + struct imx_scc_ctx *ctx; + + ctx = xzalloc(sizeof(*ctx)); + ctx->scc = scc_dev; + + ctx->ctrl = SCC_SCM_CTRL_START_CIPHER; + ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE; + ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE; + + return imx_scc_des3_op(ctx, req); +} + +static void imx_scc_hw_init(struct imx_scc *scc) +{ + int offset; + + offset = SCC_NON_RESERVED_OFFSET / scc->block_size_bytes; + + /* Fill the RED_START register */ + writel(offset, scc->base + SCC_SCM_RED_START); + + /* Fill the BLACK_START register */ + writel(offset, scc->base + SCC_SCM_BLACK_START); + + scc->red_memory = scc->base + SCC_SCM_RED_MEMORY + + SCC_NON_RESERVED_OFFSET; + + scc->black_memory = scc->base + SCC_SCM_BLACK_MEMORY + + SCC_NON_RESERVED_OFFSET; + + scc->bytes_remaining = scc->memory_size_bytes; +} + +static int imx_scc_get_config(struct imx_scc *scc) +{ + int config; + + config = readl(scc->base + SCC_SCM_CFG); + + scc->block_size_bytes = config & SCC_SCM_CFG_BLOCK_SIZE_MASK; + + scc->black_ram_size_blocks = config & SCC_SCM_CFG_BLACK_SIZE_MASK; + + scc->memory_size_bytes = (scc->block_size_bytes * + scc->black_ram_size_blocks) - + SCC_NON_RESERVED_OFFSET; + + return 0; +} + +static int imx_scc_get_state(struct imx_scc *scc) +{ + int status, ret; + const char *statestr; + + status = readl(scc->base + SCC_SMN_STATUS) & + SCC_SMN_STATUS_STATE_MASK; + + /* If in Health Check, try to bringup to secure state */ + if (status & SCC_SMN_STATE_HEALTH_CHECK) { + /* + * Write a simple algorithm to the Algorithm Sequence + * Checker (ASC) + */ + writel(0xaaaa, scc->base + SCC_SMN_SEQ_START); + writel(0x5555, scc->base + SCC_SMN_SEQ_END); + writel(0x5555, scc->base + SCC_SMN_SEQ_CHECK); + + status = readl(scc->base + SCC_SMN_STATUS) & + SCC_SMN_STATUS_STATE_MASK; + } + + switch (status) { + case SCC_SMN_STATE_NON_SECURE: + statestr = "non-secure"; + ret = 0; + break; + case SCC_SMN_STATE_SECURE: + statestr = "secure"; + ret = 0; + break; + case SCC_SMN_STATE_FAIL: + statestr = "fail"; + ret = -EIO; + break; + default: + statestr = "unknown"; + ret = -EINVAL; + break; + } + + dev_info(scc->dev, "starting in %s mode\n", statestr); + + return ret; +} + +static int imx_scc_probe(struct device_d *dev) +{ + struct imx_scc *scc; + int ret; + + scc = xzalloc(sizeof(*scc)); + + scc->base = dev_request_mem_region(dev, 0); + if (IS_ERR(scc->base)) + return PTR_ERR(scc->base); + + scc->clk = clk_get(dev, "ipg"); + if (IS_ERR(scc->clk)) { + dev_err(dev, "Could not get ipg clock\n"); + return PTR_ERR(scc->clk); + } + + clk_enable(scc->clk); + + /* clear error status register */ + + writel(0x0, scc->base + SCC_SCM_ERROR_STATUS); + + /* clear interrupt control registers */ + writel(SCC_SCM_INTR_CTRL_CLR_INTR | + SCC_SCM_INTR_CTRL_MASK_INTR, + scc->base + SCC_SCM_INTR_CTRL); + + writel(SCC_SMN_COMMAND_CLR_INTR | + SCC_SMN_COMMAND_EN_INTR, + scc->base + SCC_SMN_COMMAND); + + scc->dev = dev; + + ret = imx_scc_get_config(scc); + if (ret) + goto err_out; + + ret = imx_scc_get_state(scc); + + if (ret) { + dev_err(dev, "SCC in unusable state\n"); + goto err_out; + } + + imx_scc_hw_init(scc); + + scc_dev = scc; + + if (IS_ENABLED(CONFIG_BLOBGEN)) { + ret = imx_scc_blob_gen_probe(dev); + if (ret) + goto err_out; + } + + return 0; + +err_out: + clk_disable(scc->clk); + clk_put(scc->clk); + free(scc); + + return ret; +} + +static __maybe_unused struct of_device_id imx_scc_dt_ids[] = { + { .compatible = "fsl,imx25-scc", }, + { /* sentinel */ } +}; + +static struct driver_d imx_scc_driver = { + .name = "mxc-scc", + .probe = imx_scc_probe, + .of_compatible = imx_scc_dt_ids, +}; +device_platform_driver(imx_scc_driver); diff --git a/drivers/crypto/imx-scc/scc.h b/drivers/crypto/imx-scc/scc.h new file mode 100644 index 0000000000..5c5c25c4a0 --- /dev/null +++ b/drivers/crypto/imx-scc/scc.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +struct ablkcipher_request; + +int imx_scc_cbc_des_encrypt(struct ablkcipher_request *req); +int imx_scc_cbc_des_decrypt(struct ablkcipher_request *req); +int imx_scc_blob_gen_probe(struct device_d *dev); diff --git a/dts/Bindings/arm/cpus.yaml b/dts/Bindings/arm/cpus.yaml index 365dcf384d..82dd7582e9 100644 --- a/dts/Bindings/arm/cpus.yaml +++ b/dts/Bindings/arm/cpus.yaml @@ -228,7 +228,7 @@ patternProperties: - renesas,r9a06g032-smp - rockchip,rk3036-smp - rockchip,rk3066-smp - - socionext,milbeaut-m10v-smp + - socionext,milbeaut-m10v-smp - ste,dbx500-smp cpu-release-addr: diff --git a/dts/Bindings/hwmon/adc128d818.txt b/dts/Bindings/hwmon/adc128d818.txt index 08bab0e94d..d0ae46d7ba 100644 --- a/dts/Bindings/hwmon/adc128d818.txt +++ b/dts/Bindings/hwmon/adc128d818.txt @@ -26,7 +26,7 @@ Required node properties: Optional node properties: - - ti,mode: Operation mode (see above). + - ti,mode: Operation mode (u8) (see above). Example (operation mode 2): @@ -34,5 +34,5 @@ Example (operation mode 2): adc128d818@1d { compatible = "ti,adc128d818"; reg = <0x1d>; - ti,mode = <2>; + ti,mode = /bits/ 8 <2>; }; diff --git a/dts/Bindings/net/davinci_emac.txt b/dts/Bindings/net/davinci_emac.txt index 24c5cdaba8..ca83dcc84f 100644 --- a/dts/Bindings/net/davinci_emac.txt +++ b/dts/Bindings/net/davinci_emac.txt @@ -20,6 +20,8 @@ Required properties: Optional properties: - phy-handle: See ethernet.txt file in the same directory. If absent, davinci_emac driver defaults to 100/FULL. +- nvmem-cells: phandle, reference to an nvmem node for the MAC address +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used - ti,davinci-rmii-en: 1 byte, 1 means use RMII - ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM? diff --git a/dts/Bindings/net/ethernet.txt b/dts/Bindings/net/ethernet.txt index cfc376bc97..a686215805 100644 --- a/dts/Bindings/net/ethernet.txt +++ b/dts/Bindings/net/ethernet.txt @@ -10,15 +10,14 @@ Documentation/devicetree/bindings/phy/phy-bindings.txt. the boot program; should be used in cases where the MAC address assigned to the device by the boot program is different from the "local-mac-address" property; -- nvmem-cells: phandle, reference to an nvmem node for the MAC address; -- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used; - max-speed: number, specifies maximum speed in Mbit/s supported by the device; - max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than the maximum frame size (there's contradiction in the Devicetree Specification). - phy-mode: string, operation mode of the PHY interface. This is now a de-facto standard property; supported values are: - * "internal" + * "internal" (Internal means there is not a standard bus between the MAC and + the PHY, something proprietary is being used to embed the PHY in the MAC.) * "mii" * "gmii" * "sgmii" diff --git a/dts/Bindings/net/macb.txt b/dts/Bindings/net/macb.txt index 174f292d8a..8b80515729 100644 --- a/dts/Bindings/net/macb.txt +++ b/dts/Bindings/net/macb.txt @@ -26,6 +26,10 @@ Required properties: Optional elements: 'tsu_clk' - clocks: Phandles to input clocks. +Optional properties: +- nvmem-cells: phandle, reference to an nvmem node for the MAC address +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used + Optional properties for PHY child node: - reset-gpios : Should specify the gpio for phy reset - magic-packet : If present, indicates that the hardware supports waking diff --git a/dts/include/dt-bindings/clock/sifive-fu540-prci.h b/dts/include/dt-bindings/clock/sifive-fu540-prci.h new file mode 100644 index 0000000000..6a0b70a37d --- /dev/null +++ b/dts/include/dt-bindings/clock/sifive-fu540-prci.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018-2019 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + */ + +#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H +#define __DT_BINDINGS_CLOCK_SIFIVE_FU540_PRCI_H + +/* Clock indexes for use by Device Tree data and the PRCI driver */ + +#define PRCI_CLK_COREPLL 0 +#define PRCI_CLK_DDRPLL 1 +#define PRCI_CLK_GEMGXLPLL 2 +#define PRCI_CLK_TLCLK 3 + +#endif diff --git a/dts/include/dt-bindings/input/linux-event-codes.h b/dts/include/dt-bindings/input/linux-event-codes.h index 7f14d4a66c..64cee11692 100644 --- a/dts/include/dt-bindings/input/linux-event-codes.h +++ b/dts/include/dt-bindings/input/linux-event-codes.h @@ -439,10 +439,12 @@ #define KEY_TITLE 0x171 #define KEY_SUBTITLE 0x172 #define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 +#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */ +#define KEY_ZOOM KEY_FULL_SCREEN #define KEY_MODE 0x175 #define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 +#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */ +#define KEY_SCREEN KEY_ASPECT_RATIO #define KEY_PC 0x178 /* Media Select Computer */ #define KEY_TV 0x179 /* Media Select TV */ #define KEY_TV2 0x17a /* Media Select Cable */ diff --git a/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h b/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h index 8063e8314e..6d487c5eba 100644 --- a/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h +++ b/dts/include/dt-bindings/reset/amlogic,meson-g12a-reset.h @@ -51,7 +51,10 @@ #define RESET_SD_EMMC_A 44 #define RESET_SD_EMMC_B 45 #define RESET_SD_EMMC_C 46 -/* 47-60 */ +/* 47 */ +#define RESET_USB_PHY20 48 +#define RESET_USB_PHY21 49 +/* 50-60 */ #define RESET_AUDIO_CODEC 61 /* 62-63 */ /* RESET2 */ diff --git a/dts/src/arc/hsdk.dts b/dts/src/arc/hsdk.dts index 69bc1c9e8e..7425bb0f2d 100644 --- a/dts/src/arc/hsdk.dts +++ b/dts/src/arc/hsdk.dts @@ -18,8 +18,8 @@ model = "snps,hsdk"; compatible = "snps,hsdk"; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; chosen { bootargs = "earlycon=uart8250,mmio32,0xf0005000,115200n8 console=ttyS0,115200n8 debug print-fatal-signals=1"; @@ -105,7 +105,7 @@ #size-cells = <1>; interrupt-parent = <&idu_intc>; - ranges = <0x00000000 0xf0000000 0x10000000>; + ranges = <0x00000000 0x0 0xf0000000 0x10000000>; cgu_rst: reset-controller@8a0 { compatible = "snps,hsdk-reset"; @@ -269,9 +269,10 @@ }; memory@80000000 { - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; device_type = "memory"; - reg = <0x80000000 0x40000000>; /* 1 GiB */ + reg = <0x0 0x80000000 0x0 0x40000000>; /* 1 GB lowmem */ + /* 0x1 0x00000000 0x0 0x40000000>; 1 GB highmem */ }; }; diff --git a/dts/src/arm/am335x-evm.dts b/dts/src/arm/am335x-evm.dts index dce5be5df9..edcff79879 100644 --- a/dts/src/arm/am335x-evm.dts +++ b/dts/src/arm/am335x-evm.dts @@ -57,6 +57,24 @@ enable-active-high; }; + /* TPS79501 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS79501 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + matrix_keypad: matrix_keypad0 { compatible = "gpio-matrix-keypad"; debounce-delay-ms = <5>; @@ -499,10 +517,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/dts/src/arm/am335x-evmsk.dts b/dts/src/arm/am335x-evmsk.dts index b128998097..2c2d8b5b8c 100644 --- a/dts/src/arm/am335x-evmsk.dts +++ b/dts/src/arm/am335x-evmsk.dts @@ -73,6 +73,24 @@ enable-active-high; }; + /* TPS79518 */ + v1_8d_reg: fixedregulator-v1_8d { + compatible = "regulator-fixed"; + regulator-name = "v1_8d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* TPS78633 */ + v3_3d_reg: fixedregulator-v3_3d { + compatible = "regulator-fixed"; + regulator-name = "v3_3d"; + vin-supply = <&vbat>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + leds { pinctrl-names = "default"; pinctrl-0 = <&user_leds_s0>; @@ -501,10 +519,10 @@ status = "okay"; /* Regulators */ - AVDD-supply = <&vaux2_reg>; - IOVDD-supply = <&vaux2_reg>; - DRVDD-supply = <&vaux2_reg>; - DVDD-supply = <&vbat>; + AVDD-supply = <&v3_3d_reg>; + IOVDD-supply = <&v3_3d_reg>; + DRVDD-supply = <&v3_3d_reg>; + DVDD-supply = <&v1_8d_reg>; }; }; diff --git a/dts/src/arm/am33xx-l4.dtsi b/dts/src/arm/am33xx-l4.dtsi index f459ec316a..ca6d9f02a8 100644 --- a/dts/src/arm/am33xx-l4.dtsi +++ b/dts/src/arm/am33xx-l4.dtsi @@ -1762,7 +1762,7 @@ reg = <0xcc000 0x4>; reg-names = "rev"; /* Domains (P, C): per_pwrdm, l4ls_clkdm */ - clocks = <&l4ls_clkctrl AM3_D_CAN0_CLKCTRL 0>; + clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN0_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; @@ -1785,7 +1785,7 @@ reg = <0xd0000 0x4>; reg-names = "rev"; /* Domains (P, C): per_pwrdm, l4ls_clkdm */ - clocks = <&l4ls_clkctrl AM3_D_CAN1_CLKCTRL 0>; + clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN1_CLKCTRL 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; diff --git a/dts/src/arm/rk3288-tinker.dtsi b/dts/src/arm/rk3288-tinker.dtsi index aa107ee41b..ef653c3209 100644 --- a/dts/src/arm/rk3288-tinker.dtsi +++ b/dts/src/arm/rk3288-tinker.dtsi @@ -254,6 +254,7 @@ }; vccio_sd: LDO_REG5 { + regulator-boot-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; regulator-name = "vccio_sd"; @@ -430,7 +431,7 @@ bus-width = <4>; cap-mmc-highspeed; cap-sd-highspeed; - card-detect-delay = <200>; + broken-cd; disable-wp; /* wp not hooked up */ pinctrl-names = "default"; pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; diff --git a/dts/src/arm/rk3288-veyron.dtsi b/dts/src/arm/rk3288-veyron.dtsi index 0bc2409f69..192dbc089a 100644 --- a/dts/src/arm/rk3288-veyron.dtsi +++ b/dts/src/arm/rk3288-veyron.dtsi @@ -25,8 +25,6 @@ gpio_keys: gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pwr_key_l>; diff --git a/dts/src/arm/rk3288.dtsi b/dts/src/arm/rk3288.dtsi index ca7d52daa8..a024d1e7e7 100644 --- a/dts/src/arm/rk3288.dtsi +++ b/dts/src/arm/rk3288.dtsi @@ -70,7 +70,7 @@ compatible = "arm,cortex-a12"; reg = <0x501>; resets = <&cru SRST_CORE1>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -80,7 +80,7 @@ compatible = "arm,cortex-a12"; reg = <0x502>; resets = <&cru SRST_CORE2>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -90,7 +90,7 @@ compatible = "arm,cortex-a12"; reg = <0x503>; resets = <&cru SRST_CORE3>; - operating-points = <&cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; /* min followed by max */ clock-latency = <40000>; clocks = <&cru ARMCLK>; @@ -1119,8 +1119,6 @@ clock-names = "ref", "pclk"; power-domains = <&power RK3288_PD_VIO>; rockchip,grf = <&grf>; - #address-cells = <1>; - #size-cells = <0>; status = "disabled"; ports { @@ -1282,27 +1280,27 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - opp@100000000 { + opp-100000000 { opp-hz = /bits/ 64 <100000000>; opp-microvolt = <950000>; }; - opp@200000000 { + opp-200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <950000>; }; - opp@300000000 { + opp-300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <1000000>; }; - opp@400000000 { + opp-400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <1100000>; }; - opp@500000000 { + opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <1200000>; }; - opp@600000000 { + opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <1250000>; }; diff --git a/dts/src/arm/sama5d2-pinfunc.h b/dts/src/arm/sama5d2-pinfunc.h index 1c01a6f843..28a2e45752 100644 --- a/dts/src/arm/sama5d2-pinfunc.h +++ b/dts/src/arm/sama5d2-pinfunc.h @@ -518,7 +518,7 @@ #define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0) #define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 1, 3) #define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 2, 1) -#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 2, 1) +#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 3, 1) #define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 4, 2) #define PIN_PC10 74 #define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0) diff --git a/dts/src/arm/ste-nomadik-nhk15.dts b/dts/src/arm/ste-nomadik-nhk15.dts index f2f6558a00..04066f9cb8 100644 --- a/dts/src/arm/ste-nomadik-nhk15.dts +++ b/dts/src/arm/ste-nomadik-nhk15.dts @@ -213,13 +213,12 @@ gpio-sck = <&gpio0 5 GPIO_ACTIVE_HIGH>; gpio-mosi = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* - * This chipselect is active high. Just setting the flags - * to GPIO_ACTIVE_HIGH is not enough for the SPI DT bindings, - * it will be ignored, only the special "spi-cs-high" flag - * really counts. + * It's not actually active high, but the frameworks assume + * the polarity of the passed-in GPIO is "normal" (active + * high) then actively drives the line low to select the + * chip. */ cs-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; - spi-cs-high; num-chipselects = <1>; /* diff --git a/dts/src/arm64/altera/socfpga_stratix10.dtsi b/dts/src/arm64/altera/socfpga_stratix10.dtsi index 7c649f6b14..cd7c76e58b 100644 --- a/dts/src/arm64/altera/socfpga_stratix10.dtsi +++ b/dts/src/arm64/altera/socfpga_stratix10.dtsi @@ -162,6 +162,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 1>; + altr,sysmgr-syscon = <&sysmgr 0x44 0>; status = "disabled"; }; @@ -179,6 +180,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 2>; + altr,sysmgr-syscon = <&sysmgr 0x48 0>; status = "disabled"; }; @@ -196,6 +198,7 @@ rx-fifo-depth = <16384>; snps,multicast-filter-bins = <256>; iommus = <&smmu 3>; + altr,sysmgr-syscon = <&sysmgr 0x4c 0>; status = "disabled"; }; diff --git a/dts/src/arm64/rockchip/rk3328-roc-cc.dts b/dts/src/arm64/rockchip/rk3328-roc-cc.dts index 33c44e8572..0e34354b20 100644 --- a/dts/src/arm64/rockchip/rk3328-roc-cc.dts +++ b/dts/src/arm64/rockchip/rk3328-roc-cc.dts @@ -108,8 +108,8 @@ snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; - tx_delay = <0x25>; - rx_delay = <0x11>; + tx_delay = <0x24>; + rx_delay = <0x18>; status = "okay"; }; diff --git a/dts/src/arm64/rockchip/rk3328-rock64.dts b/dts/src/arm64/rockchip/rk3328-rock64.dts index 2157a52827..79b4d1d4b5 100644 --- a/dts/src/arm64/rockchip/rk3328-rock64.dts +++ b/dts/src/arm64/rockchip/rk3328-rock64.dts @@ -46,8 +46,7 @@ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; + gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&usb20_host_drv>; regulator-name = "vcc_host1_5v"; diff --git a/dts/src/arm64/rockchip/rk3328.dtsi b/dts/src/arm64/rockchip/rk3328.dtsi index 84f14b132e..dabef1a216 100644 --- a/dts/src/arm64/rockchip/rk3328.dtsi +++ b/dts/src/arm64/rockchip/rk3328.dtsi @@ -1445,11 +1445,11 @@ sdmmc0 { sdmmc0_clk: sdmmc0-clk { - rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_4ma>; + rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none_8ma>; }; sdmmc0_cmd: sdmmc0-cmd { - rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up_8ma>; }; sdmmc0_dectn: sdmmc0-dectn { @@ -1461,14 +1461,14 @@ }; sdmmc0_bus1: sdmmc0-bus1 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>; }; sdmmc0_bus4: sdmmc0-bus4 { - rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_4ma>, - <1 RK_PA1 1 &pcfg_pull_up_4ma>, - <1 RK_PA2 1 &pcfg_pull_up_4ma>, - <1 RK_PA3 1 &pcfg_pull_up_4ma>; + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up_8ma>, + <1 RK_PA1 1 &pcfg_pull_up_8ma>, + <1 RK_PA2 1 &pcfg_pull_up_8ma>, + <1 RK_PA3 1 &pcfg_pull_up_8ma>; }; sdmmc0_gpio: sdmmc0-gpio { @@ -1642,50 +1642,50 @@ rgmiim1_pins: rgmiim1-pins { rockchip,pins = /* mac_txclk */ - <1 RK_PB4 2 &pcfg_pull_none_12ma>, + <1 RK_PB4 2 &pcfg_pull_none_8ma>, /* mac_rxclk */ - <1 RK_PB5 2 &pcfg_pull_none_2ma>, + <1 RK_PB5 2 &pcfg_pull_none_4ma>, /* mac_mdio */ - <1 RK_PC3 2 &pcfg_pull_none_2ma>, + <1 RK_PC3 2 &pcfg_pull_none_4ma>, /* mac_txen */ - <1 RK_PD1 2 &pcfg_pull_none_12ma>, + <1 RK_PD1 2 &pcfg_pull_none_8ma>, /* mac_clk */ - <1 RK_PC5 2 &pcfg_pull_none_2ma>, + <1 RK_PC5 2 &pcfg_pull_none_4ma>, /* mac_rxdv */ - <1 RK_PC6 2 &pcfg_pull_none_2ma>, + <1 RK_PC6 2 &pcfg_pull_none_4ma>, /* mac_mdc */ - <1 RK_PC7 2 &pcfg_pull_none_2ma>, + <1 RK_PC7 2 &pcfg_pull_none_4ma>, /* mac_rxd1 */ - <1 RK_PB2 2 &pcfg_pull_none_2ma>, + <1 RK_PB2 2 &pcfg_pull_none_4ma>, /* mac_rxd0 */ - <1 RK_PB3 2 &pcfg_pull_none_2ma>, + <1 RK_PB3 2 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <1 RK_PB0 2 &pcfg_pull_none_12ma>, + <1 RK_PB0 2 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <1 RK_PB1 2 &pcfg_pull_none_12ma>, + <1 RK_PB1 2 &pcfg_pull_none_8ma>, /* mac_rxd3 */ - <1 RK_PB6 2 &pcfg_pull_none_2ma>, + <1 RK_PB6 2 &pcfg_pull_none_4ma>, /* mac_rxd2 */ - <1 RK_PB7 2 &pcfg_pull_none_2ma>, + <1 RK_PB7 2 &pcfg_pull_none_4ma>, /* mac_txd3 */ - <1 RK_PC0 2 &pcfg_pull_none_12ma>, + <1 RK_PC0 2 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <1 RK_PC1 2 &pcfg_pull_none_12ma>, + <1 RK_PC1 2 &pcfg_pull_none_8ma>, /* mac_txclk */ - <0 RK_PB0 1 &pcfg_pull_none>, + <0 RK_PB0 1 &pcfg_pull_none_8ma>, /* mac_txen */ - <0 RK_PB4 1 &pcfg_pull_none>, + <0 RK_PB4 1 &pcfg_pull_none_8ma>, /* mac_clk */ - <0 RK_PD0 1 &pcfg_pull_none>, + <0 RK_PD0 1 &pcfg_pull_none_4ma>, /* mac_txd1 */ - <0 RK_PC0 1 &pcfg_pull_none>, + <0 RK_PC0 1 &pcfg_pull_none_8ma>, /* mac_txd0 */ - <0 RK_PC1 1 &pcfg_pull_none>, + <0 RK_PC1 1 &pcfg_pull_none_8ma>, /* mac_txd3 */ - <0 RK_PC7 1 &pcfg_pull_none>, + <0 RK_PC7 1 &pcfg_pull_none_8ma>, /* mac_txd2 */ - <0 RK_PC6 1 &pcfg_pull_none>; + <0 RK_PC6 1 &pcfg_pull_none_8ma>; }; rmiim1_pins: rmiim1-pins { diff --git a/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts b/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts index 4a543f2117..844eac939a 100644 --- a/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts +++ b/dts/src/arm64/rockchip/rk3399-rock-pi-4.dts @@ -158,6 +158,7 @@ }; &hdmi { + ddc-i2c-bus = <&i2c3>; pinctrl-names = "default"; pinctrl-0 = <&hdmi_cec>; status = "okay"; diff --git a/include/base64.h b/include/base64.h new file mode 100644 index 0000000000..0df510281d --- /dev/null +++ b/include/base64.h @@ -0,0 +1,9 @@ +#ifndef __BASE64_H +#define __BASE64_H + +void uuencode(char *p, const char *src, int length); +int decode_base64(char *dst, int dst_len, const char *src); + +#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) + +#endif /* __BASE64_H */ diff --git a/include/blobgen.h b/include/blobgen.h new file mode 100644 index 0000000000..09a6637b77 --- /dev/null +++ b/include/blobgen.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __BLOBGEN_H__ +#define __BLOBGEN_H__ + +#include <common.h> + +enum access_rights { + KERNEL, + KERNEL_EVM, + USERSPACE, +}; + +#define KEYMOD_LENGTH 16 +#define MAX_BLOB_LEN 4096 +#define BLOCKSIZE_BYTES 8 + +struct blobgen { + struct device_d dev; + int (*encrypt)(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, void *blob, + int *blobsize); + int (*decrypt)(struct blobgen *bg, const char *modifier, + const void *blob, int blobsize, void **plain, + int *plainsize); + + enum access_rights access; + unsigned int max_payload_size; + + struct list_head list; +}; + +int blob_gen_register(struct device_d *dev, struct blobgen *bg); + +struct blobgen *blobgen_get(const char *name); + +int blob_encrypt(struct blobgen *blg, const char *modifier, const void *plain, + int plainsize, void **blob, int *blobsize); +int blob_encrypt_to_env(struct blobgen *blg, const char *modifier, + const void *plain, int plainsize, const char *varname); +int blob_decrypt(struct blobgen *bg, const char *modifier, const void *blob, + int blobsize, void **plain, int *plainsize); +int blob_decrypt_from_base64(struct blobgen *blg, const char *modifier, + const char *encrypted, void **plain, int *plainsize); + +#endif diff --git a/include/common.h b/include/common.h index 11d26cb3db..723b9c706c 100644 --- a/include/common.h +++ b/include/common.h @@ -68,7 +68,9 @@ int readline (const char *prompt, char *buf, int len); long get_ram_size (volatile long *, long); /* common/console.c */ -int ctrlc (void); +int ctrlc(void); +int arch_ctrlc(void); +void ctrlc_handled(void); #ifdef ARCH_HAS_STACK_DUMP void dump_stack(void); diff --git a/include/console.h b/include/console.h index 673921331d..4062e5abf6 100644 --- a/include/console.h +++ b/include/console.h @@ -207,4 +207,7 @@ static inline void pbl_set_putc(void (*putcf)(void *ctx, int c), void *ctx) {} bool console_allow_color(void); +void console_ctrlc_allow(void); +void console_ctrlc_forbid(void); + #endif diff --git a/include/console_countdown.h b/include/console_countdown.h index c6c2d5c00e..88cadf11ec 100644 --- a/include/console_countdown.h +++ b/include/console_countdown.h @@ -7,7 +7,7 @@ #define CONSOLE_COUNTDOWN_CTRLC (1 << 4) #define CONSOLE_COUNTDOWN_EXTERN (1 << 5) -int console_countdown(int timeout_s, unsigned flags, char *out_key); +int console_countdown(int timeout_s, unsigned flags, const char *keys, char *out_key); void console_countdown_abort(void); #endif /* __CONSOLE_COUNTDOWN_H */ diff --git a/include/crypto.h b/include/crypto.h new file mode 100644 index 0000000000..ac70111cab --- /dev/null +++ b/include/crypto.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __CRYPTO_H__ +#define __CRYPTO_H__ + +struct ablkcipher_request { + unsigned int nbytes; + + void __iomem *info; + + void __iomem *dst; + void __iomem *src; +}; + +#endif diff --git a/include/crypto/des.h b/include/crypto/des.h new file mode 100644 index 0000000000..58fdaaa99d --- /dev/null +++ b/include/crypto/des.h @@ -0,0 +1,16 @@ +/* + * DES & Triple DES EDE Cipher Algorithms. + */ + +#ifndef __CRYPTO_DES_H +#define __CRYPTO_DES_H + +#define DES_KEY_SIZE 8 +#define DES_EXPKEY_WORDS 32 +#define DES_BLOCK_SIZE 8 + +#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) +#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE + +#endif /* __CRYPTO_DES_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 27f62461f0..7cf6975bcc 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -57,6 +57,9 @@ config XZ_DEC_SPARC config REED_SOLOMON bool +config BASE64 + bool "include base64 encode/decode support" + config GENERIC_FIND_NEXT_BIT def_bool n @@ -155,4 +158,7 @@ config GENERIC_LIB_MULDI3 config NLS bool "Native language support" +config BLOBGEN + bool "include blob encode/decode support" + endmenu diff --git a/lib/Makefile b/lib/Makefile index 8dabf4ae77..161d3a756e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -18,6 +18,7 @@ obj-y += readkey.o obj-y += kfifo.o obj-y += libbb.o obj-y += libgen.o +obj-$(CONFIG_BLOBGEN) += blobgen.o obj-y += stringlist.o obj-y += cmdlinepart.o obj-y += recursive_action.o @@ -44,6 +45,7 @@ obj-$(CONFIG_LZ4_DECOMPRESS) += decompress_unlz4.o obj-$(CONFIG_PROCESS_ESCAPE_SEQUENCE) += process_escape_sequence.o obj-$(CONFIG_UNCOMPRESS) += uncompress.o obj-$(CONFIG_BCH) += bch.o +obj-$(CONFIG_BASE64) += base64.o obj-$(CONFIG_BITREV) += bitrev.o obj-$(CONFIG_QSORT) += qsort.o obj-$(CONFIG_LIBSCAN) += libscan.o diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 0000000000..ac165ab168 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,154 @@ +/* + * Code based on busybox-1.23.2 + * + * Copyright 2003, Glenn McGrath + * Copyright 2006, Rob Landley <rob@landley.net> + * Copyright 2010, Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include <common.h> +#include <base64.h> + +/* Conversion table. for base 64 */ +static const char uuenc_tbl_base64[65 + 1] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + '=' /* termination character */, + '\0' /* needed for uudecode.c only */ +}; + +/* + * Encode bytes at S of length LENGTH to uuencode or base64 format and place it + * to STORE. STORE will be 0-terminated, and must point to a writable + * buffer of at least 1+BASE64_LENGTH(length) bytes. + * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3)) + */ +void uuencode(char *p, const char *src, int length) +{ + const unsigned char *s = src; + const char *tbl = uuenc_tbl_base64; + + /* Transform the 3x8 bits to 4x6 bits */ + while (length > 0) { + unsigned s1, s2; + + /* Are s[1], s[2] valid or should be assumed 0? */ + s1 = s2 = 0; + length -= 3; /* can be >=0, -1, -2 */ + if (length >= -1) { + s1 = s[1]; + if (length >= 0) + s2 = s[2]; + } + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)]; + *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)]; + *p++ = tbl[s2 & 0x3f]; + s += 3; + } + /* Zero-terminate */ + *p = '\0'; + /* If length is -2 or -1, pad last char or two */ + while (length) { + *--p = tbl[64]; + length++; + } +} +EXPORT_SYMBOL(uuencode); + +/* + * Decode base64 encoded string. Stops on '\0'. + * + */ +int decode_base64(char *p_dst, int dst_len, const char *src) +{ + const char *src_tail; + char *dst = p_dst; + int length = 0; + + while (dst_len > 0) { + unsigned char six_bit[4]; + int count = 0; + + /* Fetch up to four 6-bit values */ + src_tail = src; + while (count < 4) { + const char *table_ptr; + int ch; + + /* + * Get next _valid_ character. + * uuenc_tbl_base64[] contains this string: + * 0 1 2 3 4 5 6 + * 01234567890123456789012345678901234567890123456789012345678901234 + * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + */ + do { + ch = *src; + if (ch == '\0') { + /* + * Example: + * If we decode "QUJD <NUL>", we want + * to return ptr to NUL, not to ' ', + * because we did fully decode + * the string (to "ABC"). + */ + if (count == 0) + src_tail = src; + goto ret; + } + src++; + table_ptr = strchr(uuenc_tbl_base64, ch); + } while (!table_ptr); + + /* Convert encoded character to decimal */ + ch = table_ptr - uuenc_tbl_base64; + + /* ch is 64 if char was '=', otherwise 0..63 */ + if (ch == 64) + break; + + six_bit[count] = ch; + count++; + } + + /* + * Transform 6-bit values to 8-bit ones. + * count can be < 4 when we decode the tail: + * "eQ==" -> "y", not "y NUL NUL". + * Note that (count > 1) is always true, + * "x===" encoding is not valid: + * even a single zero byte encodes as "AA==". + * However, with current logic we come here with count == 1 + * when we decode "==" tail. + */ + if (count > 1) + *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; + if (count > 2) + *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; + if (count > 3) + *dst++ = six_bit[2] << 6 | six_bit[3]; + /* + * Note that if we decode "AA==" and ate first '=', + * we just decoded one char (count == 2) and now we'll + * do the loop once more to decode second '='. + */ + dst_len -= count-1; + /* last character was "=" */ + if (count != 0) + length += count - 1; + } +ret: + p_dst = dst; + + return length; +} +EXPORT_SYMBOL(decode_base64); diff --git a/lib/blobgen.c b/lib/blobgen.c new file mode 100644 index 0000000000..5a556a68ce --- /dev/null +++ b/lib/blobgen.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * 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. + * + */ +#include <blobgen.h> +#include <base64.h> +#include <malloc.h> +#include <crypto.h> +#include <dma.h> +#include <environment.h> + +static LIST_HEAD(blobs); +static struct blobgen *bg_default; + +/** + * blob_gen_register - register a blob device + * @dev: The parent device + * @bg: The blobgen device + * + * This registers a blob device. Returns 0 for success or a negative error + * code otherwise. + */ +int blob_gen_register(struct device_d *dev, struct blobgen *bg) +{ + int ret; + + dev_set_name(&bg->dev, "blob"); + bg->dev.parent = dev; + + ret = register_device(&bg->dev); + if (ret) + return ret; + + list_add_tail(&bg->list, &blobs); + + if (!bg_default) + bg_default = bg; + + return 0; +} + +/** + * blobgen_get - get a blob generator of given name + * @name: The name of the blob generator to look for + * + * Finds a blob generator by name and returns it. Returns NULL if none is found. + */ +struct blobgen *blobgen_get(const char *name) +{ + struct device_d *dev; + struct blobgen *bg; + + if (!name) + return bg_default; + + dev = get_device_by_name(name); + if (!dev) + return NULL; + + list_for_each_entry(bg, &blobs, list) { + if (dev == &bg->dev) + return bg; + } + + return NULL; +} + +/** + * blob_encrypt - encrypt a data blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @plain: The plaintext input + * @plainsize: Length of the plain data in bytes + * @retblob: The encrypted blob is returned here + * @blobsize: The returned length of the encrypted blob + * + * This encrypts a blob passed in @plain to an allocated buffer returned in + * @retblob. Returns 0 for success or a negative error code otherwise. @retblob + * is valid when the function returns successfully. The caller must free the + * buffer after use. + */ +int blob_encrypt(struct blobgen *bg, const char *modifier, const void *plain, + int plainsize, void **retblob, int *blobsize) +{ + void *blob; + int ret; + + if (plainsize > bg->max_payload_size) + return -EINVAL; + + pr_debug("%s plain:\n", __func__); + pr_memory_display(MSG_DEBUG, plain, 0, plainsize, 1, 0); + + blob = dma_alloc(MAX_BLOB_LEN); + if (!blob) + return -ENOMEM; + + ret = bg->encrypt(bg, modifier, plain, plainsize, blob, blobsize); + + if (ret) { + free(blob); + } else { + pr_debug("%s encrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, blob, 0, *blobsize, 1, 0); + *retblob = blob; + } + + return ret; +} + +/** + * blob_encrypt_to_env - encrypt blob to environment variable + * @bg: The blob generator to use + * @modifier: Modifier string + * @plain: The plaintext input + * @plainsize: Length of the plain data in bytes + * @varname: Name of the variable to set with the output blob + * + * This uses blob_encrypt to encrypt a blob. The result is base64 encoded and + * written to the environment variable @varname. Returns 0 for success or a + * negative error code otherwise. + */ +int blob_encrypt_to_env(struct blobgen *bg, const char *modifier, + const void *plain, int plainsize, const char *varname) +{ + int ret; + int blobsize; + void *blob; + char *value; + + ret = blob_encrypt(bg, modifier, plain, plainsize, &blob, &blobsize); + if (ret) + return ret; + + value = malloc(BASE64_LENGTH(blobsize) + 1); + if (!value) + return -ENOMEM; + + uuencode(value, blob, blobsize); + + pr_debug("%s encrypted base64: \"%s\"\n", __func__, value); + + ret = setenv(varname, value); + + free(value); + free(blob); + + return ret; +} + +/** + * blob_decrypt - decrypt a blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @blob: The encrypted blob + * @blobsize: Size of the encrypted blob + * @plain: Plaintext is returned here + * @plainsize: Size of the data returned in bytes + * + * This function decrypts a blob generated with blob_encrypt. @modifier must match + * the modifier used to encrypt the data. Returns 0 when the data could be + * decrypted successfully or a negative error code otherwise. + */ +int blob_decrypt(struct blobgen *bg, const char *modifier, const void *blob, + int blobsize, void **plain, int *plainsize) +{ + int ret; + + pr_debug("%s encrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, blob, 0, blobsize, 1, 0); + + ret = bg->decrypt(bg, modifier, blob, blobsize, plain, plainsize); + + if (!ret) { + pr_debug("%s decrypted:\n", __func__); + pr_memory_display(MSG_DEBUG, *plain, 0, *plainsize, 1, 0); + } + + return ret; +} + +/** + * blob_decrypt_from_base64 - decrypt a base64 encoded blob + * @bg: The blob generator to use + * @modifier: Modifier string + * @encrypted: base64 encoded encrypted data + * @plain: Plaintext is returned here + * @plainsize: Size of the data returned in bytes + * + * like blob_decrypt, but takes the encrypted data as a base64 encoded string. + * Returns 0 when the data could be decrypted successfully or a negative error + * code otherwise. + */ +int blob_decrypt_from_base64(struct blobgen *bg, const char *modifier, + const char *encrypted, void **plain, + int *plainsize) +{ + char *data; + int ret, len; + + data = dma_alloc(MAX_BLOB_LEN); + if (!data) + return -ENOMEM; + + pr_debug("encrypted base64: \"%s\"\n", encrypted); + + len = decode_base64(data, MAX_BLOB_LEN, encrypted); + + ret = blob_decrypt(bg, modifier, data, len, plain, plainsize); + + free(data); + + return ret; +} |