diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | drivers/auth/mbedtls/mbedtls_x509_parser.c | 39 | ||||
-rw-r--r-- | drivers/synopsys/emmc/dw_mmc.c | 424 | ||||
-rw-r--r-- | include/drivers/synopsys/dw_mmc.h | 45 | ||||
-rw-r--r-- | include/lib/aarch32/arch_helpers.h | 7 | ||||
-rw-r--r-- | include/lib/aarch64/arch_helpers.h | 14 | ||||
-rw-r--r-- | include/lib/libfdt/fdt.h | 2 | ||||
-rw-r--r-- | include/lib/libfdt/libfdt.h | 244 | ||||
-rw-r--r-- | lib/libfdt/fdt.c | 13 | ||||
-rw-r--r-- | lib/libfdt/fdt_ro.c | 154 | ||||
-rw-r--r-- | lib/libfdt/fdt_rw.c | 8 | ||||
-rw-r--r-- | lib/libfdt/fdt_wip.c | 29 | ||||
-rw-r--r-- | make_helpers/build_macros.mk | 12 | ||||
-rw-r--r-- | tools/fiptool/fiptool.c | 31 |
14 files changed, 943 insertions, 83 deletions
@@ -66,7 +66,7 @@ INC_DIRS_TO_CHECK := $(sort $(filter-out \ include/lib, \ $(wildcard include/*))) LIB_DIRS_TO_CHECK := $(sort $(filter-out \ - lib/libfdt \ + lib/libfdt% \ lib/stdlib, \ $(wildcard lib/*))) ROOT_DIRS_TO_CHECK := $(sort $(filter-out \ @@ -568,7 +568,7 @@ realclean distclean: checkcodebase: locate-checkpatch @echo " CHECKING STYLE" @if test -d .git ; then \ - git ls-files | grep -E -v libfdt\|stdlib\|docs\|\.md | \ + git ls-files | grep -E -v 'libfdt|stdlib|docs|\.md' | \ while read GIT_FILE ; \ do ${CHECKPATCH} ${CHECKCODE_ARGS} -f $$GIT_FILE ; \ done ; \ diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c index 1a6a9a75..73da9d1e 100644 --- a/drivers/auth/mbedtls/mbedtls_x509_parser.c +++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,6 +36,7 @@ * extensions field, such as an image hash or a public key. */ +#include <arch_helpers.h> #include <assert.h> #include <img_parser_mod.h> #include <mbedtls_common.h> @@ -64,6 +65,26 @@ static mbedtls_asn1_buf sig_alg; static mbedtls_asn1_buf signature; /* + * Clear all static temporary variables. + */ +static void clear_temp_vars(void) +{ +#define ZERO_AND_CLEAN(x) \ + do { \ + memset(&x, 0, sizeof(x)); \ + clean_dcache_range((uintptr_t)&x, sizeof(x)); \ + } while (0); + + ZERO_AND_CLEAN(tbs) + ZERO_AND_CLEAN(v3_ext); + ZERO_AND_CLEAN(pk); + ZERO_AND_CLEAN(sig_alg); + ZERO_AND_CLEAN(signature); + +#undef ZERO_AND_CLEAN +} + +/* * Get X509v3 extension * * Global variable 'v3_ext' must point to the extensions region @@ -134,7 +155,12 @@ static int get_ext(const char *oid, void **ext, unsigned int *ext_len) /* * Check the integrity of the certificate ASN.1 structure. + * * Extract the relevant data that will be used later during authentication. + * + * This function doesn't clear the static variables located on the top of this + * file in case of an error. It is only called from check_integrity(), which + * performs the cleanup if necessary. */ static int cert_parse(void *img, unsigned int img_len) { @@ -398,9 +424,18 @@ static void init(void) mbedtls_init(); } +/* + * Wrapper for cert_parse() that clears the static variables used by it in case + * of an error. + */ static int check_integrity(void *img, unsigned int img_len) { - return cert_parse(img, img_len); + int rc = cert_parse(img, img_len); + + if (rc != IMG_PARSER_OK) + clear_temp_vars(); + + return rc; } /* diff --git a/drivers/synopsys/emmc/dw_mmc.c b/drivers/synopsys/emmc/dw_mmc.c new file mode 100644 index 00000000..5b156837 --- /dev/null +++ b/drivers/synopsys/emmc/dw_mmc.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <delay_timer.h> +#include <dw_mmc.h> +#include <emmc.h> +#include <errno.h> +#include <mmio.h> +#include <string.h> + +#define DWMMC_CTRL (0x00) +#define CTRL_IDMAC_EN (1 << 25) +#define CTRL_DMA_EN (1 << 5) +#define CTRL_INT_EN (1 << 4) +#define CTRL_DMA_RESET (1 << 2) +#define CTRL_FIFO_RESET (1 << 1) +#define CTRL_RESET (1 << 0) +#define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \ + CTRL_RESET) + +#define DWMMC_PWREN (0x04) +#define DWMMC_CLKDIV (0x08) +#define DWMMC_CLKSRC (0x0c) +#define DWMMC_CLKENA (0x10) +#define DWMMC_TMOUT (0x14) +#define DWMMC_CTYPE (0x18) +#define CTYPE_8BIT (1 << 16) +#define CTYPE_4BIT (1) +#define CTYPE_1BIT (0) + +#define DWMMC_BLKSIZ (0x1c) +#define DWMMC_BYTCNT (0x20) +#define DWMMC_INTMASK (0x24) +#define INT_EBE (1 << 15) +#define INT_SBE (1 << 13) +#define INT_HLE (1 << 12) +#define INT_FRUN (1 << 11) +#define INT_DRT (1 << 9) +#define INT_RTO (1 << 8) +#define INT_DCRC (1 << 7) +#define INT_RCRC (1 << 6) +#define INT_RXDR (1 << 5) +#define INT_TXDR (1 << 4) +#define INT_DTO (1 << 3) +#define INT_CMD_DONE (1 << 2) +#define INT_RE (1 << 1) + +#define DWMMC_CMDARG (0x28) +#define DWMMC_CMD (0x2c) +#define CMD_START (1 << 31) +#define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */ +#define CMD_UPDATE_CLK_ONLY (1 << 21) +#define CMD_SEND_INIT (1 << 15) +#define CMD_STOP_ABORT_CMD (1 << 14) +#define CMD_WAIT_PRVDATA_COMPLETE (1 << 13) +#define CMD_WRITE (1 << 10) +#define CMD_DATA_TRANS_EXPECT (1 << 9) +#define CMD_CHECK_RESP_CRC (1 << 8) +#define CMD_RESP_LEN (1 << 7) +#define CMD_RESP_EXPECT (1 << 6) +#define CMD(x) (x & 0x3f) + +#define DWMMC_RESP0 (0x30) +#define DWMMC_RESP1 (0x34) +#define DWMMC_RESP2 (0x38) +#define DWMMC_RESP3 (0x3c) +#define DWMMC_RINTSTS (0x44) +#define DWMMC_STATUS (0x48) +#define STATUS_DATA_BUSY (1 << 9) + +#define DWMMC_FIFOTH (0x4c) +#define FIFOTH_TWMARK(x) (x & 0xfff) +#define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16) +#define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28) + +#define DWMMC_DEBNCE (0x64) +#define DWMMC_BMOD (0x80) +#define BMOD_ENABLE (1 << 7) +#define BMOD_FB (1 << 1) +#define BMOD_SWRESET (1 << 0) + +#define DWMMC_DBADDR (0x88) +#define DWMMC_IDSTS (0x8c) +#define DWMMC_IDINTEN (0x90) +#define DWMMC_CARDTHRCTL (0x100) +#define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16) +#define CARDTHRCTL_RD_THR_EN (1 << 0) + +#define IDMAC_DES0_DIC (1 << 1) +#define IDMAC_DES0_LD (1 << 2) +#define IDMAC_DES0_FS (1 << 3) +#define IDMAC_DES0_CH (1 << 4) +#define IDMAC_DES0_ER (1 << 5) +#define IDMAC_DES0_CES (1 << 30) +#define IDMAC_DES0_OWN (1 << 31) +#define IDMAC_DES1_BS1(x) ((x) & 0x1fff) +#define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) + +#define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8) + +#define DWMMC_8BIT_MODE (1 << 6) + +#define TIMEOUT 100000 + +struct dw_idmac_desc { + unsigned int des0; + unsigned int des1; + unsigned int des2; + unsigned int des3; +}; + +static void dw_init(void); +static int dw_send_cmd(emmc_cmd_t *cmd); +static int dw_set_ios(int clk, int width); +static int dw_prepare(int lba, uintptr_t buf, size_t size); +static int dw_read(int lba, uintptr_t buf, size_t size); +static int dw_write(int lba, uintptr_t buf, size_t size); + +static const emmc_ops_t dw_mmc_ops = { + .init = dw_init, + .send_cmd = dw_send_cmd, + .set_ios = dw_set_ios, + .prepare = dw_prepare, + .read = dw_read, + .write = dw_write, +}; + +static dw_mmc_params_t dw_params; + +static void dw_update_clk(void) +{ + unsigned int data; + + mmio_write_32(dw_params.reg_base + DWMMC_CMD, + CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY | + CMD_START); + while (1) { + data = mmio_read_32(dw_params.reg_base + DWMMC_CMD); + if ((data & CMD_START) == 0) + break; + data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); + assert(data & INT_HLE); + } +} + +static void dw_set_clk(int clk) +{ + unsigned int data; + int div; + + assert(clk > 0); + + for (div = 1; div < 256; div++) { + if ((dw_params.clk_rate / (2 * div)) <= clk) { + break; + } + } + assert(div < 256); + + /* wait until controller is idle */ + do { + data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS); + } while (data & STATUS_DATA_BUSY); + + /* disable clock before change clock rate */ + mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0); + dw_update_clk(); + + mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div); + dw_update_clk(); + + /* enable clock */ + mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1); + mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0); + dw_update_clk(); +} + +static void dw_init(void) +{ + unsigned int data; + uintptr_t base; + + assert((dw_params.reg_base & EMMC_BLOCK_MASK) == 0); + + base = dw_params.reg_base; + mmio_write_32(base + DWMMC_PWREN, 1); + mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL); + do { + data = mmio_read_32(base + DWMMC_CTRL); + } while (data); + + /* enable DMA in CTRL */ + data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN; + mmio_write_32(base + DWMMC_CTRL, data); + mmio_write_32(base + DWMMC_RINTSTS, ~0); + mmio_write_32(base + DWMMC_INTMASK, 0); + mmio_write_32(base + DWMMC_TMOUT, ~0); + mmio_write_32(base + DWMMC_IDINTEN, ~0); + mmio_write_32(base + DWMMC_BLKSIZ, EMMC_BLOCK_SIZE); + mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024); + mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff); + mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET); + do { + data = mmio_read_32(base + DWMMC_BMOD); + } while (data & BMOD_SWRESET); + /* enable DMA in BMOD */ + data |= BMOD_ENABLE | BMOD_FB; + mmio_write_32(base + DWMMC_BMOD, data); + + udelay(100); + dw_set_clk(EMMC_BOOT_CLK_RATE); + udelay(100); +} + +static int dw_send_cmd(emmc_cmd_t *cmd) +{ + unsigned int op, data, err_mask; + uintptr_t base; + int timeout; + + assert(cmd); + + base = dw_params.reg_base; + + switch (cmd->cmd_idx) { + case EMMC_CMD0: + op = CMD_SEND_INIT; + break; + case EMMC_CMD12: + op = CMD_STOP_ABORT_CMD; + break; + case EMMC_CMD13: + op = CMD_WAIT_PRVDATA_COMPLETE; + break; + case EMMC_CMD8: + case EMMC_CMD17: + case EMMC_CMD18: + op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; + break; + case EMMC_CMD24: + case EMMC_CMD25: + op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | + CMD_WAIT_PRVDATA_COMPLETE; + break; + default: + op = 0; + break; + } + op |= CMD_USE_HOLD_REG | CMD_START; + switch (cmd->resp_type) { + case 0: + break; + case EMMC_RESPONSE_R2: + op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC | + CMD_RESP_LEN; + break; + case EMMC_RESPONSE_R3: + op |= CMD_RESP_EXPECT; + break; + default: + op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC; + break; + } + timeout = TIMEOUT; + do { + data = mmio_read_32(base + DWMMC_STATUS); + if (--timeout <= 0) + panic(); + } while (data & STATUS_DATA_BUSY); + + mmio_write_32(base + DWMMC_RINTSTS, ~0); + mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg); + mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx); + + err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE | + INT_DCRC | INT_DRT | INT_SBE; + timeout = TIMEOUT; + do { + udelay(500); + data = mmio_read_32(base + DWMMC_RINTSTS); + + if (data & err_mask) + return -EIO; + if (data & INT_DTO) + break; + if (--timeout == 0) { + ERROR("%s, RINTSTS:0x%x\n", __func__, data); + panic(); + } + } while (!(data & INT_CMD_DONE)); + + if (op & CMD_RESP_EXPECT) { + cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0); + if (op & CMD_RESP_LEN) { + cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1); + cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2); + cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3); + } + } + return 0; +} + +static int dw_set_ios(int clk, int width) +{ + switch (width) { + case EMMC_BUS_WIDTH_1: + mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT); + break; + case EMMC_BUS_WIDTH_4: + mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT); + break; + case EMMC_BUS_WIDTH_8: + mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT); + break; + default: + assert(0); + } + dw_set_clk(clk); + return 0; +} + +static int dw_prepare(int lba, uintptr_t buf, size_t size) +{ + struct dw_idmac_desc *desc; + int desc_cnt, i, last; + uintptr_t base; + + assert(((buf & EMMC_BLOCK_MASK) == 0) && + ((size % EMMC_BLOCK_SIZE) == 0) && + (dw_params.desc_size > 0) && + ((dw_params.reg_base & EMMC_BLOCK_MASK) == 0) && + ((dw_params.desc_base & EMMC_BLOCK_MASK) == 0) && + ((dw_params.desc_size & EMMC_BLOCK_MASK) == 0)); + + desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) / + DWMMC_DMA_MAX_BUFFER_SIZE; + assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size); + + base = dw_params.reg_base; + desc = (struct dw_idmac_desc *)dw_params.desc_base; + mmio_write_32(base + DWMMC_BYTCNT, size); + mmio_write_32(base + DWMMC_RINTSTS, ~0); + for (i = 0; i < desc_cnt; i++) { + desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; + desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE); + desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i; + desc[i].des3 = dw_params.desc_base + + (sizeof(struct dw_idmac_desc)) * (i + 1); + } + /* first descriptor */ + desc->des0 |= IDMAC_DES0_FS; + /* last descriptor */ + last = desc_cnt - 1; + (desc + last)->des0 |= IDMAC_DES0_LD; + (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH); + (desc + last)->des1 = IDMAC_DES1_BS1(size - (last * + DWMMC_DMA_MAX_BUFFER_SIZE)); + /* set next descriptor address as 0 */ + (desc + last)->des3 = 0; + + mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base); + clean_dcache_range(dw_params.desc_base, + desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); + + return 0; +} + +static int dw_read(int lba, uintptr_t buf, size_t size) +{ + return 0; +} + +static int dw_write(int lba, uintptr_t buf, size_t size) +{ + return 0; +} + +void dw_mmc_init(dw_mmc_params_t *params) +{ + assert((params != 0) && + ((params->reg_base & EMMC_BLOCK_MASK) == 0) && + ((params->desc_base & EMMC_BLOCK_MASK) == 0) && + ((params->desc_size & EMMC_BLOCK_MASK) == 0) && + (params->desc_size > 0) && + (params->clk_rate > 0) && + ((params->bus_width == EMMC_BUS_WIDTH_1) || + (params->bus_width == EMMC_BUS_WIDTH_4) || + (params->bus_width == EMMC_BUS_WIDTH_8))); + + memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); + emmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, + params->flags); +} diff --git a/include/drivers/synopsys/dw_mmc.h b/include/drivers/synopsys/dw_mmc.h new file mode 100644 index 00000000..22192f89 --- /dev/null +++ b/include/drivers/synopsys/dw_mmc.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DW_MMC_H__ +#define __DW_MMC_H__ + +typedef struct dw_mmc_params { + uintptr_t reg_base; + uintptr_t desc_base; + size_t desc_size; + int clk_rate; + int bus_width; + unsigned int flags; +} dw_mmc_params_t; + +void dw_mmc_init(dw_mmc_params_t *params); + +#endif /* __DW_MMC_H__ */ diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h index 7955d62e..3a82a7b3 100644 --- a/include/lib/aarch32/arch_helpers.h +++ b/include/lib/aarch32/arch_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +33,7 @@ #include <arch.h> /* for additional register definitions */ #include <stdint.h> -#include <types.h> +#include <sys/types.h> /********************************************************************** * Macros which create inline functions to read or write CPU system @@ -187,6 +187,9 @@ void flush_dcache_range(uintptr_t addr, size_t size); void clean_dcache_range(uintptr_t addr, size_t size); void inv_dcache_range(uintptr_t addr, size_t size); +void dcsw_op_louis(u_register_t op_type); +void dcsw_op_all(u_register_t op_type); + void disable_mmu_secure(void); void disable_mmu_icache_secure(void); diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index aa262031..d70c9aee 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,6 +34,7 @@ #include <arch.h> /* for additional register definitions */ #include <cdefs.h> /* For __dead2 */ #include <stdint.h> +#include <sys/types.h> /********************************************************************** * Macros which create inline functions to read or write CPU system @@ -143,11 +144,12 @@ DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w) -void flush_dcache_range(uint64_t, uint64_t); -void clean_dcache_range(uint64_t, uint64_t); -void inv_dcache_range(uint64_t, uint64_t); -void dcsw_op_louis(uint32_t); -void dcsw_op_all(uint32_t); +void flush_dcache_range(uintptr_t addr, size_t size); +void clean_dcache_range(uintptr_t addr, size_t size); +void inv_dcache_range(uintptr_t addr, size_t size); + +void dcsw_op_louis(u_register_t op_type); +void dcsw_op_all(u_register_t op_type); void disable_mmu_el3(void); void disable_mmu_icache_el3(void); diff --git a/include/lib/libfdt/fdt.h b/include/lib/libfdt/fdt.h index 63319983..c833dc1b 100644 --- a/include/lib/libfdt/fdt.h +++ b/include/lib/libfdt/fdt.h @@ -53,7 +53,7 @@ */ /* - * Portions copyright (c) 2016, ARM Limited and Contributors. + * Portions copyright (c) 2016-2017, ARM Limited and Contributors. * All rights reserved. */ diff --git a/include/lib/libfdt/libfdt.h b/include/lib/libfdt/libfdt.h index 74f48955..f6623785 100644 --- a/include/lib/libfdt/libfdt.h +++ b/include/lib/libfdt/libfdt.h @@ -52,7 +52,7 @@ */ /* - * Portions copyright (c) 2016, ARM Limited and Contributors. + * Portions copyright (c) 2016-2017, ARM Limited and Contributors. * All rights reserved. */ @@ -126,7 +126,12 @@ /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells * or similar property with a bad format or value */ -#define FDT_ERR_MAX 14 +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ + +#define FDT_ERR_MAX 15 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -168,27 +173,55 @@ int fdt_first_subnode(const void *fdt, int offset); */ int fdt_next_subnode(const void *fdt, int offset); +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + * + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic) @@ -259,6 +292,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); const char *fdt_string(const void *fdt, int stroffset); /** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +uint32_t fdt_get_max_phandle(const void *fdt); + +/** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * @@ -318,8 +366,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -328,6 +377,17 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); /** + * fdt_path_offset_namelen - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * @namelen: number of characters of path to consider + * + * Identical to fdt_path_offset(), but only consider the first namelen + * characters of path as the path name. + */ +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); + +/** * fdt_path_offset - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate @@ -340,7 +400,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); * address). * * returns: - * structure block offset of the node with the requested path (>=0), on success + * structure block offset of the node with the requested path (>=0), on + * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, @@ -364,10 +425,12 @@ int fdt_path_offset(const void *fdt, const char *path); * * returns: * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings @@ -416,6 +479,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); int fdt_next_property_offset(const void *fdt, int offset); /** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property_offset: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + +/** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob * @offset: offset of the property to retrieve @@ -451,8 +541,8 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, @@ -479,7 +569,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -543,6 +634,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} /** * fdt_getprop - retrieve the value of a given property @@ -564,7 +662,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -636,7 +735,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, @@ -666,11 +765,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * structure from the start to nodeoffset. * * returns: - * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -692,7 +791,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, * * returns: * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -715,7 +814,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -755,7 +854,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -802,7 +901,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -839,7 +938,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -862,6 +961,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); +/** + * fdt_stringlist_count - count the number of strings in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @return: + * the number of strings in the given property + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); + +/** + * fdt_stringlist_search - find a string in a string list and return its index + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @string: string to look up in the string list + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @return: + * the index of the string in the list of strings + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist or does not contain + * the given string + */ +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * @return: + * A pointer to the string at the given index in the string list or NULL on + * failure. On success the length of the string will be stored in the memory + * location pointed to by the lenp parameter, if non-NULL. On failure one of + * the following negative error codes will be returned in the lenp parameter + * (if non-NULL): + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int index, + int *lenp); + /**********************************************************************/ /* Read-only functions (addressing related) */ /**********************************************************************/ @@ -887,7 +1048,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -907,7 +1069,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -922,6 +1085,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset); /**********************************************************************/ /** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); + +/** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change @@ -1531,9 +1715,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * returns: - * structure block offset of the created nodeequested subnode (>=0), on success + * structure block offset of the created nodeequested subnode (>=0), on + * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c index 2ce6a441..22286a1a 100644 --- a/lib/libfdt/fdt.c +++ b/lib/libfdt/fdt.c @@ -76,18 +76,19 @@ int fdt_check_header(const void *fdt) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - const char *p; + unsigned absoffset = offset + fdt_off_dt_struct(fdt); + + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; - p = _fdt_offset_ptr(fdt, offset); - - if (p + len < p) - return NULL; - return p; + return _fdt_offset_ptr(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index 50007f61..04590984 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strlen(p) == len) && (memcmp(p, s, len) == 0); } +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -154,9 +180,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } -int fdt_path_offset(const void *fdt, const char *path) +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) { - const char *end = path + strlen(path); + const char *end = path + namelen; const char *p = path; int offset = 0; @@ -164,7 +190,7 @@ int fdt_path_offset(const void *fdt, const char *path) /* see if we have an alias */ if (*path != '/') { - const char *q = strchr(path, '/'); + const char *q = memchr(path, '/', end - p); if (!q) q = end; @@ -177,14 +203,15 @@ int fdt_path_offset(const void *fdt, const char *path) p = q; } - while (*p) { + while (p < end) { const char *q; - while (*p == '/') + while (*p == '/') { p++; - if (! *p) - return offset; - q = strchr(p, '/'); + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); if (! q) q = end; @@ -198,6 +225,11 @@ int fdt_path_offset(const void *fdt, const char *path) return offset; } +int fdt_path_offset(const void *fdt, const char *path) +{ + return fdt_path_offset_namelen(fdt, path, strlen(path)); +} + const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); @@ -532,6 +564,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) return 0; } +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { @@ -541,10 +673,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; + + return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c index 70adec6c..2eed4f58 100644 --- a/lib/libfdt/fdt_rw.c +++ b/lib/libfdt/fdt_rw.c @@ -101,6 +101,8 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); @@ -189,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; + return _fdt_splice_mem_rsv(fdt, re, 1, 0); } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index c5bbb68d..6aaab399 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -55,21 +55,42 @@ #include "libfdt_internal.h" +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { - void *propval; + const void *propval; int proplen; - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; - memcpy(propval, val, len); - return 0; + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void _fdt_nop_region(void *start, int len) diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index bf9dc794..2312d2c9 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -227,11 +227,12 @@ endef # MAKE_LD generate the linker script using the C preprocessor # $(1) = output linker script # $(2) = input template +# $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_LD $(eval DEP := $(1).d) -$(1): $(2) | $(dir ${1}) +$(1): $(2) | bl$(3)_dirs @echo " PP $$<" $$(Q)$$(CPP) $$(CPPFLAGS) -P -D__ASSEMBLY__ -D__LINKER__ $(MAKE_DEP) -o $$@ $$< @@ -297,11 +298,10 @@ define MAKE_BL $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE)) # We use sort only to get a list of unique object directory names. # ordering is not relevant but sort removes duplicates. - $(eval TEMP_OBJ_DIRS := $(sort $(BUILD_DIR)/ $(dir ${OBJS}))) + $(eval TEMP_OBJ_DIRS := $(sort $(BUILD_DIR)/ $(dir ${OBJS} ${LINKERFILE}))) # The $(dir ) function leaves a trailing / on the directory names - # We append a . then strip /. from each, to remove the trailing / characters - # This gives names suitable for use as make rule targets. - $(eval OBJ_DIRS := $(subst /.,,$(addsuffix .,$(TEMP_OBJ_DIRS)))) + # Rip off the / to match directory names with make rule targets. + $(eval OBJ_DIRS := $(patsubst %/,%,$(TEMP_OBJ_DIRS))) # Create generators for object directory structure @@ -314,7 +314,7 @@ $(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},))) bl${1}_dirs: | ${OBJ_DIRS} $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) -$(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE))) +$(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1))) $(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs @echo " LD $$@" diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index fc0c8d66..6145e26d 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -155,12 +155,17 @@ static void *xmalloc(size_t size, const char *msg) return d; } +static void *xzalloc(size_t size, const char *msg) +{ + return memset(xmalloc(size, msg), 0, size); +} + static image_desc_t *new_image_desc(const uuid_t *uuid, const char *name, const char *cmdline_name) { image_desc_t *desc; - desc = xmalloc(sizeof(*desc), + desc = xzalloc(sizeof(*desc), "failed to allocate memory for image descriptor"); memcpy(&desc->uuid, uuid, sizeof(uuid_t)); desc->name = xstrdup(name, @@ -168,7 +173,6 @@ static image_desc_t *new_image_desc(const uuid_t *uuid, desc->cmdline_name = xstrdup(cmdline_name, "failed to allocate memory for image command line name"); desc->action = DO_UNSPEC; - desc->action_arg = NULL; return desc; } @@ -196,9 +200,14 @@ static void free_image_desc(image_desc_t *desc) static void add_image_desc(image_desc_t *desc) { + image_desc_t **p = &image_desc_head; + assert(lookup_image_desc_from_uuid(&desc->uuid) == NULL); - desc->next = image_desc_head; - image_desc_head = desc; + + while (*p) + p = &(*p)->next; + + *p = desc; nr_image_descs++; } @@ -233,9 +242,15 @@ static void fill_image_descs(void) static void add_image(image_t *image) { + image_t **p = &image_head; + assert(lookup_image_from_uuid(&image->uuid) == NULL); - image->next = image_head; - image_head = image; + + while (*p) + p = &(*p)->next; + + *p = image; + nr_images++; } @@ -393,7 +408,7 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out) * Build a new image out of the ToC entry and add it to the * table of images. */ - image = xmalloc(sizeof(*image), + image = xzalloc(sizeof(*image), "failed to allocate memory for image"); memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); image->buffer = xmalloc(toc_entry->size, @@ -450,7 +465,7 @@ static image_t *read_image_from_file(const uuid_t *uuid, const char *filename) if (fstat(fileno(fp), &st) == -1) log_errx("fstat %s", filename); - image = xmalloc(sizeof(*image), "failed to allocate memory for image"); + image = xzalloc(sizeof(*image), "failed to allocate memory for image"); memcpy(&image->uuid, uuid, sizeof(uuid_t)); image->buffer = xmalloc(st.st_size, "failed to allocate image buffer"); if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) |