Merge git://www.denx.de/git/u-boot-marvell

This commit is contained in:
Tom Rini 2017-02-01 06:57:35 -05:00
commit f77309d343
22 changed files with 1973 additions and 192 deletions

View File

@ -957,7 +957,8 @@ MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \
-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
-T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \
$(if $(KEYDIR),-k $(KEYDIR))
MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage

View File

@ -1,5 +1,9 @@
if ARCH_MVEBU
config HAVE_MVEBU_EFUSE
bool
default n
config ARMADA_32BIT
bool
select CPU_V7
@ -23,6 +27,7 @@ config ARMADA_375
config ARMADA_38X
bool
select ARMADA_32BIT
select HAVE_MVEBU_EFUSE
config ARMADA_XP
bool
@ -146,4 +151,34 @@ config SYS_VENDOR
config SYS_SOC
default "mvebu"
config MVEBU_EFUSE
bool "Enable eFuse support"
default n
depends on HAVE_MVEBU_EFUSE
help
Enable support for reading and writing eFuses on mvebu SoCs.
config MVEBU_EFUSE_FAKE
bool "Fake eFuse access (dry run)"
default n
depends on MVEBU_EFUSE
help
This enables a "dry run" mode where eFuses are not really programmed.
Instead the eFuse accesses are emulated by writing to and reading
from a memory block.
This is can be used for testing prog scripts.
config SECURED_MODE_IMAGE
bool "Build image for trusted boot"
default false
depends on 88F6820
help
Build an image that employs the ARMADA SoC's trusted boot framework
for securely booting images.
config SECURED_MODE_CSK_INDEX
int "Index of active CSK"
default 0
depends on SECURED_MODE_IMAGE
endif

View File

@ -27,6 +27,7 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o
obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o
obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o
obj-$(CONFIG_MVEBU_EFUSE) += efuse.o
endif # CONFIG_SPL_BUILD
obj-y += gpio.o
obj-y += mbus.o

264
arch/arm/mach-mvebu/efuse.c Normal file
View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/efuse.h>
#include <asm/arch/soc.h>
#include <linux/mbus.h>
#if defined(CONFIG_MVEBU_EFUSE_FAKE)
#define DRY_RUN
#else
#undef DRY_RUN
#endif
#define MBUS_EFUSE_BASE 0xF6000000
#define MBUS_EFUSE_SIZE BIT(20)
#define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008))
enum {
MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31),
};
struct mvebu_hd_efuse {
u32 bits_31_0;
u32 bits_63_32;
u32 bit64;
u32 reserved0;
};
#ifndef DRY_RUN
static struct mvebu_hd_efuse *efuses =
(struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000);
#else
static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1];
#endif
static int efuse_initialised;
static struct mvebu_hd_efuse *get_efuse_line(int nr)
{
if (nr < 0 || nr > 63 || !efuse_initialised)
return NULL;
return efuses + nr;
}
static void enable_efuse_program(void)
{
#ifndef DRY_RUN
setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
#endif
}
static void disable_efuse_program(void)
{
#ifndef DRY_RUN
clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
#endif
}
static int do_prog_efuse(struct mvebu_hd_efuse *efuse,
struct efuse_val *new_val, u32 mask0, u32 mask1)
{
struct efuse_val val;
val.dwords.d[0] = readl(&efuse->bits_31_0);
val.dwords.d[1] = readl(&efuse->bits_63_32);
val.lock = readl(&efuse->bit64);
if (val.lock & 1)
return -EPERM;
val.dwords.d[0] |= (new_val->dwords.d[0] & mask0);
val.dwords.d[1] |= (new_val->dwords.d[1] & mask1);
val.lock |= new_val->lock;
writel(val.dwords.d[0], &efuse->bits_31_0);
mdelay(1);
writel(val.dwords.d[1], &efuse->bits_63_32);
mdelay(1);
writel(val.lock, &efuse->bit64);
mdelay(5);
return 0;
}
static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1)
{
struct mvebu_hd_efuse *efuse;
int res = 0;
res = mvebu_efuse_init_hw();
if (res)
return res;
efuse = get_efuse_line(nr);
if (!efuse)
return -ENODEV;
if (!new_val)
return -EINVAL;
/* only write a fuse line with lock bit */
if (!new_val->lock)
return -EINVAL;
/* according to specs ECC protection bits must be 0 on write */
if (new_val->bytes.d[7] & 0xFE)
return -EINVAL;
if (!new_val->dwords.d[0] && !new_val->dwords.d[1] && (mask0 | mask1))
return 0;
enable_efuse_program();
res = do_prog_efuse(efuse, new_val, mask0, mask1);
disable_efuse_program();
return res;
}
int mvebu_efuse_init_hw(void)
{
int ret;
if (efuse_initialised)
return 0;
ret = mvebu_mbus_add_window_by_id(
CPU_TARGET_SATA23_DFX, 0xA, MBUS_EFUSE_BASE, MBUS_EFUSE_SIZE);
if (ret)
return ret;
efuse_initialised = 1;
return 0;
}
int mvebu_read_efuse(int nr, struct efuse_val *val)
{
struct mvebu_hd_efuse *efuse;
int res;
res = mvebu_efuse_init_hw();
if (res)
return res;
efuse = get_efuse_line(nr);
if (!efuse)
return -ENODEV;
if (!val)
return -EINVAL;
val->dwords.d[0] = readl(&efuse->bits_31_0);
val->dwords.d[1] = readl(&efuse->bits_63_32);
val->lock = readl(&efuse->bit64);
return 0;
}
int mvebu_write_efuse(int nr, struct efuse_val *val)
{
return prog_efuse(nr, val, ~0, ~0);
}
int mvebu_lock_efuse(int nr)
{
struct efuse_val val = {
.lock = 1,
};
return prog_efuse(nr, &val, 0, 0);
}
/*
* wrapper funcs providing the fuse API
*
* we use the following mapping:
* "bank" -> eFuse line
* "word" -> 0: bits 0-31
* 1: bits 32-63
* 2: bit 64 (lock)
*/
static struct efuse_val prog_val;
static int valid_prog_words;
int fuse_read(u32 bank, u32 word, u32 *val)
{
struct efuse_val fuse_line;
int res;
if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
return -EINVAL;
res = mvebu_read_efuse(bank, &fuse_line);
if (res)
return res;
if (word < 2)
*val = fuse_line.dwords.d[word];
else
*val = fuse_line.lock;
return res;
}
int fuse_sense(u32 bank, u32 word, u32 *val)
{
/* not supported */
return -ENOSYS;
}
int fuse_prog(u32 bank, u32 word, u32 val)
{
int res = 0;
/*
* NOTE: Fuse line should be written as whole.
* So how can we do that with this API?
* For now: remember values for word == 0 and word == 1 and write the
* whole line when word == 2.
* This implies that we always require all 3 fuse prog cmds (one for
* for each word) to write a single fuse line.
* Exception is a single write to word 2 which will lock the fuse line.
*
* Hope that will be OK.
*/
if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
return -EINVAL;
if (word < 2) {
prog_val.dwords.d[word] = val;
valid_prog_words |= (1 << word);
} else if ((valid_prog_words & 3) == 0 && val) {
res = mvebu_lock_efuse(bank);
valid_prog_words = 0;
} else if ((valid_prog_words & 3) != 3 || !val) {
res = -EINVAL;
} else {
prog_val.lock = val != 0;
res = mvebu_write_efuse(bank, &prog_val);
valid_prog_words = 0;
}
return res;
}
int fuse_override(u32 bank, u32 word, u32 val)
{
/* not supported */
return -ENOSYS;
}

View File

@ -36,7 +36,9 @@ enum cpu_target {
CPU_TARGET_ETH01 = 0x7,
CPU_TARGET_PCIE13 = 0x8,
CPU_TARGET_SASRAM = 0x9,
CPU_TARGET_SATA01 = 0xa, /* A38X */
CPU_TARGET_NAND = 0xd,
CPU_TARGET_SATA23_DFX = 0xe, /* A38X */
};
enum cpu_attrib {

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2015 Reinhard Pfau <reinhard.pfau@gdsys.cc>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _MVEBU_EFUSE_H
#define _MVEBU_EFUSE_H
#include <common.h>
struct efuse_val {
union {
struct {
u8 d[8];
} bytes;
struct {
u16 d[4];
} words;
struct {
u32 d[2];
} dwords;
};
u32 lock;
};
#if defined(CONFIG_ARMADA_38X)
enum efuse_line {
EFUSE_LINE_SECURE_BOOT = 24,
EFUSE_LINE_PUBKEY_DIGEST_0 = 26,
EFUSE_LINE_PUBKEY_DIGEST_1 = 27,
EFUSE_LINE_PUBKEY_DIGEST_2 = 28,
EFUSE_LINE_PUBKEY_DIGEST_3 = 29,
EFUSE_LINE_PUBKEY_DIGEST_4 = 30,
EFUSE_LINE_CSK_0_VALID = 31,
EFUSE_LINE_CSK_1_VALID = 32,
EFUSE_LINE_CSK_2_VALID = 33,
EFUSE_LINE_CSK_3_VALID = 34,
EFUSE_LINE_CSK_4_VALID = 35,
EFUSE_LINE_CSK_5_VALID = 36,
EFUSE_LINE_CSK_6_VALID = 37,
EFUSE_LINE_CSK_7_VALID = 38,
EFUSE_LINE_CSK_8_VALID = 39,
EFUSE_LINE_CSK_9_VALID = 40,
EFUSE_LINE_CSK_10_VALID = 41,
EFUSE_LINE_CSK_11_VALID = 42,
EFUSE_LINE_CSK_12_VALID = 43,
EFUSE_LINE_CSK_13_VALID = 44,
EFUSE_LINE_CSK_14_VALID = 45,
EFUSE_LINE_CSK_15_VALID = 46,
EFUSE_LINE_FLASH_ID = 47,
EFUSE_LINE_BOX_ID = 48,
EFUSE_LINE_MIN = 0,
EFUSE_LINE_MAX = 63,
};
#endif
int mvebu_efuse_init_hw(void);
int mvebu_read_efuse(int nr, struct efuse_val *val);
int mvebu_write_efuse(int nr, struct efuse_val *val);
int mvebu_lock_efuse(int nr);
#endif

View File

@ -67,6 +67,7 @@
#define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000))
#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000))
#define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000))
#define MVEBU_REG_PCIE0_BASE (MVEBU_REGISTER(0x80000))
#define MVEBU_AXP_SATA_BASE (MVEBU_REGISTER(0xa0000))
#define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000))
#define MVEBU_NAND_BASE (MVEBU_REGISTER(0xd0000))

View File

@ -13,6 +13,11 @@
#include "ctrl_pex.h"
#include "sys_env_lib.h"
__weak void board_pex_config(void)
{
/* nothing in this weak default implementation */
}
int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
{
u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
@ -77,6 +82,9 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
/* Support gen1/gen2 */
DEBUG_INIT_FULL_S("Support gen1/gen2\n");
board_pex_config();
next_busno = 0;
mdelay(150);

View File

@ -83,4 +83,6 @@ int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off);
void board_pex_config(void);
#endif

View File

@ -13,8 +13,6 @@
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
static u32 get_boot_device(void)
{
u32 val;

View File

@ -43,15 +43,6 @@
#define CCDM_AUTO_FIRST_STAGE
#endif
/* enums from TCG specs */
enum {
/* capability areas */
TPM_CAP_NV_INDEX = 0x00000011,
TPM_CAP_HANDLE = 0x00000014,
/* resource types */
TPM_RT_KEY = 0x00000001,
};
/* CCDM specific contants */
enum {
/* NV indices */

View File

@ -646,6 +646,64 @@ TPM_COMMAND_NO_ARG(tpm_end_oiap)
#endif /* CONFIG_TPM_AUTH_SESSIONS */
#ifdef CONFIG_TPM_FLUSH_RESOURCES
static int do_tpm_flush(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
int type = 0;
if (argc != 2)
return CMD_RET_USAGE;
if (strcasecmp(argv[1], "key"))
type = TPM_RT_KEY;
else if (strcasecmp(argv[1], "auth"))
type = TPM_RT_AUTH;
else if (strcasecmp(argv[1], "hash"))
type = TPM_RT_HASH;
else if (strcasecmp(argv[1], "trans"))
type = TPM_RT_TRANS;
else if (strcasecmp(argv[1], "context"))
type = TPM_RT_CONTEXT;
else if (strcasecmp(argv[1], "counter"))
type = TPM_RT_COUNTER;
else if (strcasecmp(argv[1], "delegate"))
type = TPM_RT_DELEGATE;
else if (strcasecmp(argv[1], "daa_tpm"))
type = TPM_RT_DAA_TPM;
else if (strcasecmp(argv[1], "daa_v0"))
type = TPM_RT_DAA_V0;
else if (strcasecmp(argv[1], "daa_v1"))
type = TPM_RT_DAA_V1;
if (strcasecmp(argv[2], "all")) {
uint16_t res_count;
uint8_t buf[288];
uint8_t *ptr;
int err;
uint i;
/* fetch list of already loaded resources in the TPM */
err = tpm_get_capability(TPM_CAP_HANDLE, type, buf,
sizeof(buf));
if (err)
return -1;
res_count = get_unaligned_be16(buf);
ptr = buf + 2;
for (i = 0; i < res_count; ++i, ptr += 4)
tpm_flush_specific(get_unaligned_be32(ptr), type);
} else {
uint32_t handle = simple_strtoul(argv[2], NULL, 0);
if (!handle)
return -1;
tpm_flush_specific(cpu_to_be32(handle), type);
}
return 0;
}
#endif /* CONFIG_TPM_FLUSH_RESOURCES */
#define MAKE_TPM_CMD_ENTRY(cmd) \
U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
@ -701,6 +759,10 @@ static cmd_tbl_t tpm_commands[] = {
U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1,
do_tpm_get_pub_key_oiap, "", ""),
#endif /* CONFIG_TPM_AUTH_SESSIONS */
#ifdef CONFIG_TPM_FLUSH_RESOURCES
U_BOOT_CMD_MKENT(flush, 0, 1,
do_tpm_flush, "", ""),
#endif /* CONFIG_TPM_FLUSH_RESOURCES */
};
static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@ -750,6 +812,14 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
" get_capability cap_area sub_cap addr count\n"
" - Read <count> bytes of TPM capability indexed by <cap_area> and\n"
" <sub_cap> to memory address <addr>.\n"
#ifdef CONFIG_TPM_FLUSH_RESOURCES
"Resource management functions\n"
" flush resource_type id\n"
" - flushes a resource of type <resource_type> (may be one of key, auth,\n"
" hash, trans, context, counter, delegate, daa_tpm, daa_v0, daa_v1),\n"
" and id <id> from the TPM. Use an <id> of \"all\" to flush all\n"
" resources of that type.\n"
#endif /* CONFIG_TPM_FLUSH_RESOURCES */
#ifdef CONFIG_TPM_AUTH_SESSIONS
"Storage functions\n"
" loadkey2_oiap parent_handle key_addr key_len usage_auth\n"

View File

@ -0,0 +1,373 @@
The trusted boot framework on Marvell Armada 38x
================================================
Contents:
1. Overview of the trusted boot
2. Terminology
3. Boot image layout
4. The secured header
5. The secured boot flow
6. Usage example
7. Work to be done
8. Bibliography
1. Overview of the trusted boot
-------------------------------
The Armada's trusted boot framework enables the SoC to cryptographically verify
a specially prepared boot image. This can be used to establish a chain of trust
from the boot firmware all the way to the OS.
To achieve this, the Armada SoC requires a specially prepared boot image, which
contains the relevant cryptographic data, as well as other information
pertaining to the boot process. Furthermore, a eFuse structure (a
one-time-writeable memory) need to be configured in the correct way.
Roughly, the secure boot process works as follows:
* Load the header block of the boot image, extract a special "root" public RSA
key from it, and verify its SHA-256 hash against a SHA-256 stored in a eFuse
field.
* Load an array of code signing public RSA keys from the header block, and
verify its RSA signature (contained in the header block as well) using the
"root" RSA key.
* Choose a code signing key, and use it to verify the header block (excluding
the key array).
* Verify the binary image's signature (contained in the header block) using the
code signing key.
* If all checks pass successfully, boot the image.
The chain of trust is thus as follows:
* The SHA-256 value in the eFuse field verifies the "root" public key.
* The "root" public key verifies the code signing key array.
* The selected code signing key verifies the header block and the binary image.
In the special case of building a boot image containing U-Boot as the binary
image, which employs this trusted boot framework, the following tasks need to
be addressed:
1. Creation of the needed cryptographic key material.
2. Creation of a conforming boot image containing the U-Boot image as binary
image.
3. Burning the necessary eFuse values.
(1) will be addressed later, (2) will be taken care of by U-Boot's build
system (some user configuration is required, though), and for (3) the necessary
data (essentially a series of U-Boot commands to be entered at the U-Boot
command prompt) will be created by the build system as well.
The documentation of the trusted boot mode is contained in part 1, chapter
7.2.5 in the functional specification [1], and in application note [2].
2. Terminology
--------------
CSK - Code Signing Key(s): An array of RSA key pairs, which
are used to sign and verify the secured header and the
boot loader image.
KAK - Key Authentication Key: A RSA key pair, which is used
to sign and verify the array of CSKs.
Header block - The first part of the boot image, which contains the
image's headers (also known as "headers block", "boot
header", and "image header")
eFuse - A one-time-writeable memory.
BootROM - The Armada's built-in boot firmware, which is
responsible for verifying and starting secure images.
Boot image - The complete image the SoC's boot firmware loads
(contains the header block and the binary image)
Main header - The header in the header block containing information
and data pertaining to the boot process (used for both
the regular and secured boot processes)
Binary image - The binary code payload of the boot image; in this
case the U-Boot's code (also known as "source image",
or just "image")
Secured header - The specialized header in the header block that
contains information and data pertaining to the
trusted boot (also known as "security header")
Secured boot mode - A special boot mode of the Armada SoC in which secured
images are verified (non-secure images won't boot);
the mode is activated by setting a eFuse field.
Trusted debug mode - A special mode for the trusted boot that allows
debugging of devices employing the trusted boot
framework in a secure manner (untested in the current
implementation).
Trusted boot framework - The ARMADA SoC's implementation of a secure verified
boot process.
3. Boot image layout
--------------------
+-- Boot image --------------------------------------------+
| |
| +-- Header block --------------------------------------+ |
| | Main header | |
| +------------------------------------------------------+ |
| | Secured header | |
| +------------------------------------------------------+ |
| | BIN header(s) | |
| +------------------------------------------------------+ |
| | REG header(s) | |
| +------------------------------------------------------+ |
| | Padding | |
| +------------------------------------------------------+ |
| |
| +------------------------------------------------------+ |
| | Binary image + checksum | |
| +------------------------------------------------------+ |
+----------------------------------------------------------+
4. The secured header
---------------------
For the trusted boot framework, a additional header is added to the boot image.
The following data are relevant for the secure boot:
KAK: The KAK is contained in the secured header in the form
of a RSA-2048 public key in DER format with a length of
524 bytes.
Header block signature: The RSA signature of the header block (excluding the
CSK array), created using the selected CSK.
Binary image signature: The RSA signature of the binary image, created using
the selected CSK.
CSK array: The array of the 16 CSKs as RSA-2048 public keys in DER
format with a length of 8384 = 16 * 524 bytes.
CSK block signature: The RSA signature of the CSK array, created using the
KAK.
NOTE: The JTAG delay, Box ID, and Flash ID header fields do play a role in the
trusted boot process to enable and configure secure debugging, but they were
not tested in the current implementation of the trusted boot in U-Boot.
5. The secured boot flow
------------------------
The steps in the boot flow that are relevant for the trusted boot framework
proceed as follows:
1) Check if trusted boot is enabled, and perform regular boot if it is not.
2) Load the secured header, and verify its checksum.
3) Select the lowest valid CSK from CSK0 to CSK15.
4) Verify the SHA-256 hash of the KAK embedded in the secured header.
5) Verify the RSA signature of the CSK block from the secured header with the
KAK.
6) Verify the header block signature (which excludes the CSK block) from the
secured header with the selected CSK.
7) Load the binary image to the main memory and verify its checksum.
8) Verify the binary image's RSA signature from the secured header with the
selected CSK.
9) Continue the boot process as in the case of the regular boot.
NOTE: All RSA signatures are verified according to the PKCS #1 v2.1 standard
described in [3].
NOTE: The Box ID and Flash ID are checked after step 6, and the trusted debug
mode may be entered there, but since this mode is untested in the current
implementation, it is not described further.
6. Usage example
----------------
### Create key material
To employ the trusted boot framework, cryptographic key material needs to be
created. In the current implementation, two keys are needed to build a valid
secured boot image: The KAK private key and a CSK private key (both have to be
2048 bit RSA keys in PEM format). Note that the usage of more than one CSK is
currently not supported.
NOTE: Since the public key can be generated from the private key, it is
sufficient to store the private key for each key pair.
OpenSSL can be used to generate the needed files kwb_kak.key and kwb_csk.key
(the names of these files have to be configured, see the next section on
kwbimage.cfg settings):
openssl genrsa -out kwb_kak.key 2048
openssl genrsa -out kwb_csk.key 2048
The generated files have to be placed in the U-Boot root directory.
Alternatively, instead of copying the files, symlinks to the private keys can
be placed in the U-Boot root directory.
WARNING: Knowledge of the KAK or CSK private key would enable an attacker to
generate secured boot images containing arbitrary code. Hence, the private keys
should be carefully guarded.
### Create/Modifiy kwbimage.cfg
The Kirkwook architecture in U-Boot employs a special board-specific
configuration file (kwbimage.cfg), which controls various boot image settings
that are interpreted by the BootROM, such as the boot medium. The support the
trusted boot framework, several new options were added to faciliate
configuration of the secured boot.
The configuration file's layout has been retained, only the following new
options were added:
KAK - The name of the KAK RSA private key file in the U-Boot
root directory, without the trailing extension of ".key".
CSK - The name of the (active) CSK RSA private key file in the
U-Boot root directory, without the trailing extension of
".key".
BOX_ID - The BoxID to be used for trusted debugging (a integer
value).
FLASH_ID - The FlashID to be used for trusted debugging (a integer
value).
JTAG_DELAY - The JTAG delay to be used for trusted debugging (a
integer value).
CSK_INDEX - The index of the active CSK (a integer value).
SEC_SPECIALIZED_IMG - Flag to indicate whether to include the BoxID and FlashID
in the image (that is, whether to use the trusted debug
mode or not); no parameters.
SEC_BOOT_DEV - The boot device from which the trusted boot is allowed to
proceed, identified via a numeric ID. The tested values
are 0x34 = NOR flash, 0x31 = SDIO/MMC card; for
additional ID values, consult the documentation in [1].
SEC_FUSE_DUMP - Dump the "fuse prog" commands necessary for writing the
correct eFuse values to a text file in the U-Boot root
directory. The parameter is the architecture for which to
dump the commands (currently only "a38x" is supported).
The parameter values may be hardcoded into the file, but it is also possible to
employ a dynamic approach of creating a Autoconf-like kwbimage.cfg.in, then
reading configuration values from Kconfig options or from the board config
file, and generating the actual kwbimage.cfg from this template using Makefile
mechanisms (see board/gdsys/a38x/Makefile as an example for this approach).
### Set config options
To enable the generation of trusted boot images, the corresponding support
needs to be activated, and a index for the active CSK needs to be selected as
well.
Furthermore, eFuse writing support has to be activated in order to burn the
eFuse structure's values (this option is just needed for programming the eFuse
structure; production boot images may disable it).
ARM architecture
-> [*] Build image for trusted boot
(0) Index of active CSK
-> [*] Enable eFuse support
[ ] Fake eFuse access (dry run)
### Build and test boot image
The creation of the boot image is done via the usual invocation of make (with a
suitably set CROSS_COMPILE environment variable, of course). The resulting boot
image u-boot-spl.kwb can then be tested, if so desired. The hdrparser from [5]
can be used for this purpose. To build the tool, invoke make in the
'tools/marvell/doimage_mv' directory of [5], which builds a stand-alone
hdrparser executable. A test can be conducted by calling hdrparser with the
produced boot image and the following (mandatory) parameters:
./hdrparser -k 0 -t u-boot-spl.kwb
Here we assume that the CSK index is 0 and the boot image file resides in the
same directory (adapt accordingly if needed). The tool should report that all
checksums are valid ("GOOD"), that all signature verifications succeed
("PASSED"), and, finally, that the overall test was successful
("T E S T S U C C E E D E D" in the last line of output).
### Burn eFuse structure
+----------------------------------------------------------+
| WARNING: Burning the eFuse structure is a irreversible |
| operation! Should wrong or corrupted values be used, the |
| board won't boot anymore, and recovery is likely |
| impossible! |
+----------------------------------------------------------+
After the build process has finished, and the SEC_FUSE_DUMP option was set in
the kwbimage.cfg was set, a text file kwb_fuses_a38x.txt should be present in
the U-Boot top-level directory. It contains all the necessary commands to set
the eFuse structure to the values needed for the used KAK digest, as well as
the CSK index, Flash ID and Box ID that were selected in kwbimage.cfg.
Sequentially executing the commands in this file at the U-Boot command prompt
will write these values to the eFuse structure.
If the SEC_FUSE_DUMP option was not set, the commands needed to burn the fuses
have to be crafted by hand. The needed fuse lines can be looked up in [1]; a
rough overview of the process is:
* Burn the KAK public key hash. The hash itself can be found in the file
pub_kak_hash.txt in the U-Boot top-level directory; be careful to account for
the endianness!
* Burn the CSK selection, BoxID, and FlashID
* Enable trusted boot by burning the corresponding fuse (WARNING: this must be
the last fuse line written!)
* Lock the unused fuse lines
The command to employ is the "fuse prog" command previously enabled by setting
the corresponding configuration option.
For the trusted boot, the fuse prog command has a special syntax, since the
ARMADA SoC demands that whole fuse lines (64 bit values) have to be written as
a whole. The fuse prog command itself allows lists of 32 bit words to be
written at a time, but this is translated to a series of single 32 bit write
operations to the fuse line, where the individual 32 bit words are identified
by a "word" counter that is increased for each write.
To work around this restriction, we interpret each line to have three "words"
(0-2): The first and second words are the values to be written to the fuse
line, and the third is a lock flag, which is supposed to lock the fuse line
when set to 1. Writes to the first and second words are memoized between
function calls, and the fuse line is only really written and locked (on writing
the third word) if both words were previously set, so that "incomplete" writes
are prevented. An exception to this is a single write to the third word (index
2) without previously writing neither the first nor the second word, which
locks the fuse line without setting any value; this is needed to lock the
unused fuse lines.
As an example, to write the value 0011223344556677 to fuse line 10, we would
use the following command:
fuse prog -y 10 0 00112233 44556677 1
Here 10 is the fuse line number, 0 is the index of the first word to be
written, 00112233 and 44556677 are the values to be written to the fuse line
(first and second word) and the trailing 1 is the value for the third word
responsible for locking the line.
A "lock-only" command would look like this:
fuse prog -y 11 2 1
Here 11 is the fuse number, 2 is the index of the first word to be written
(notice that we only write to word 2 here; the third word for fuse line
locking), and the 1 is the value for the word we are writing to.
WARNING: According to application note [4], the VHV pin of the SoC must be
connected to a 1.8V source during eFuse programming, but *must* be disconnected
for normal operation. The AN [4] describes a software-controlled circuit (based
on a N-channel or P-channel FET and a free GPIO pin of the SoC) to achieve
this, but a jumper-based circuit should suffice as well. Regardless of the
chosen circuit, the issue needs to be addressed accordingly!
7. Work to be done
------------------
* Add the ability to populate more than one CSK
* Test secure debug
* Test on Armada XP
8. Bibliography
---------------
[1] ARMADA(R) 38x Family High-Performance Single/Dual CPU System on Chip
Functional Specification; MV-S109094-00, Rev. C; August 2, 2015,
Preliminary
[2] AN-383: ARMADA(R) 38x Families Secure Boot Mode Support; MV-S302501-00
Rev. A; March 11, 2015, Preliminary
[3] Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography
Specifications Version 2.1; February 2003;
https://www.ietf.org/rfc/rfc3447.txt
[4] AN-389: ARMADA(R) VHV Power; MV-S302545-00 Rev. B; January 28, 2016,
Released
[5] Marvell Armada 38x U-Boot support; November 25, 2015;
https://github.com/MarvellEmbeddedProcessors/u-boot-marvell
2017-01-05, Mario Six <mario.six@gdsys.cc>

View File

@ -480,6 +480,49 @@ static int m88e1310_config(struct phy_device *phydev)
return genphy_config_aneg(phydev);
}
static int m88e1680_config(struct phy_device *phydev)
{
/*
* As per Marvell Release Notes - Alaska V 88E1680 Rev A2
* Errata Section 4.1
*/
u16 reg;
int res;
/* Matrix LED mode (not neede if single LED mode is used */
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004);
reg = phy_read(phydev, MDIO_DEVAD_NONE, 27);
reg |= (1 << 5);
phy_write(phydev, MDIO_DEVAD_NONE, 27, reg);
/* QSGMII TX amplitude change */
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd);
phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53);
phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d);
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
/* EEE initialization */
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff);
phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030);
phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c);
phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc);
phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c);
phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c);
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140);
res = genphy_config_aneg(phydev);
if (res < 0)
return res;
/* soft reset */
reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
reg |= BMCR_RESET;
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg);
return 0;
}
static struct phy_driver M88E1011S_driver = {
.name = "Marvell 88E1011S",
.uid = 0x1410c60,
@ -580,6 +623,16 @@ static struct phy_driver M88E1310_driver = {
.shutdown = &genphy_shutdown,
};
static struct phy_driver M88E1680_driver = {
.name = "Marvell 88E1680",
.uid = 0x1410ed0,
.mask = 0xffffff0,
.features = PHY_GBIT_FEATURES,
.config = &m88e1680_config,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
int phy_marvell_init(void)
{
phy_register(&M88E1310_driver);
@ -592,6 +645,7 @@ int phy_marvell_init(void)
phy_register(&M88E1011S_driver);
phy_register(&M88E1510_driver);
phy_register(&M88E1518_driver);
phy_register(&M88E1680_driver);
return 0;
}

View File

@ -91,25 +91,26 @@ static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
#if defined(CONFIG_ARMADA_38X)
#define PCIE_BASE(if) \
((if) == 0 ? \
MVEBU_REG_PCIE_BASE + 0x40000 : \
MVEBU_REG_PCIE_BASE + 0x4000 * (if))
MVEBU_REG_PCIE0_BASE : \
(MVEBU_REG_PCIE_BASE + 0x4000 * (if - 1)))
/*
* On A38x MV6820 these PEX ports are supported:
* 0 - Port 0.0
* 1 - Port 0.1
* 2 - Port 0.2
* 1 - Port 1.0
* 2 - Port 2.0
* 3 - Port 3.0
*/
#define MAX_PEX 3
#define MAX_PEX 4
static struct mvebu_pcie pcie_bus[MAX_PEX];
static void mvebu_get_port_lane(struct mvebu_pcie *pcie, int pex_idx,
int *mem_target, int *mem_attr)
{
u8 port[] = { 0, 1, 2 };
u8 lane[] = { 0, 0, 0 };
u8 target[] = { 8, 4, 4 };
u8 attr[] = { 0xe8, 0xe8, 0xd8 };
u8 port[] = { 0, 1, 2, 3 };
u8 lane[] = { 0, 0, 0, 0 };
u8 target[] = { 8, 4, 4, 4 };
u8 attr[] = { 0xe8, 0xe8, 0xd8, 0xb8 };
pcie->port = port[pex_idx];
pcie->lane = lane[pex_idx];
@ -351,9 +352,9 @@ void pci_init_board(void)
mvebu_get_port_lane(pcie, i, &mem_target, &mem_attr);
/* Don't read at all from pci registers if port power is down */
if (pcie->lane == 0 && SELECT(soc_ctrl, pcie->port) == 0) {
i += 3;
debug("%s: skipping port %d\n", __func__, pcie->port);
if (SELECT(soc_ctrl, pcie->port) == 0) {
if (pcie->lane == 0)
debug("%s: skipping port %d\n", __func__, pcie->port);
continue;
}

View File

@ -884,11 +884,10 @@ void comphy_dedicated_phys_init(void)
}
node = fdt_node_offset_by_compatible(blob, -1,
"marvell,armada-3700-sdio");
"marvell,armada-8k-sdhci");
if (node <= 0) {
debug("No SDIO node in DT, looking for MMC one\n");
node = fdt_node_offset_by_compatible(blob, -1,
"marvell,xenon-sdhci");
node = fdt_node_offset_by_compatible(
blob, -1, "marvell,armada-3700-sdhci");
}
if (node > 0) {

View File

@ -82,4 +82,10 @@ config TPM_ST33ZP24_SPI
to the device using the standard TPM Interface Specification (TIS)
protocol
config TPM_FLUSH_RESOURCES
bool "Enable TPM resource flushing support"
depends on TPM
help
Enable support to flush specific resources (e.g. keys) from the TPM.
The functionality is available via the 'tpm' command as well.
endmenu

View File

@ -47,6 +47,42 @@ enum tpm_nv_index {
TPM_NV_INDEX_DIR = 0x10000001,
};
enum tpm_resource_type {
TPM_RT_KEY = 0x00000001,
TPM_RT_AUTH = 0x00000002,
TPM_RT_HASH = 0x00000003,
TPM_RT_TRANS = 0x00000004,
TPM_RT_CONTEXT = 0x00000005,
TPM_RT_COUNTER = 0x00000006,
TPM_RT_DELEGATE = 0x00000007,
TPM_RT_DAA_TPM = 0x00000008,
TPM_RT_DAA_V0 = 0x00000009,
TPM_RT_DAA_V1 = 0x0000000A,
};
enum tpm_capability_areas {
TPM_CAP_ORD = 0x00000001,
TPM_CAP_ALG = 0x00000002,
TPM_CAP_PID = 0x00000003,
TPM_CAP_FLAG = 0x00000004,
TPM_CAP_PROPERTY = 0x00000005,
TPM_CAP_VERSION = 0x00000006,
TPM_CAP_KEY_HANDLE = 0x00000007,
TPM_CAP_CHECK_LOADED = 0x00000008,
TPM_CAP_SYM_MODE = 0x00000009,
TPM_CAP_KEY_STATUS = 0x0000000C,
TPM_CAP_NV_LIST = 0x0000000D,
TPM_CAP_MFR = 0x00000010,
TPM_CAP_NV_INDEX = 0x00000011,
TPM_CAP_TRANS_ALG = 0x00000012,
TPM_CAP_HANDLE = 0x00000014,
TPM_CAP_TRANS_ES = 0x00000015,
TPM_CAP_AUTH_ENCRYPT = 0x00000017,
TPM_CAP_SELECT_SIZE = 0x00000018,
TPM_CAP_DA_LOGIC = 0x00000019,
TPM_CAP_VERSION_VAL = 0x0000001A,
};
#define TPM_NV_PER_GLOBALLOCK (1U << 15)
#define TPM_NV_PER_PPWRITE (1U << 0)
#define TPM_NV_PER_READ_STCLEAR (1U << 31)
@ -594,4 +630,13 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags);
*/
uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm);
/**
* Flush a resource with a given handle and type from the TPM
*
* @param key_handle handle of the resource
* @param resource_type type of the resource
* @return return code of the operation
*/
uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type);
#endif /* __TPM_H */

View File

@ -645,6 +645,35 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
return 0;
}
#ifdef CONFIG_TPM_FLUSH_RESOURCES
uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type)
{
const uint8_t command[18] = {
0x00, 0xc1, /* TPM_TAG */
0x00, 0x00, 0x00, 0x12, /* parameter size */
0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
0x00, 0x00, 0x00, 0x00, /* key handle */
0x00, 0x00, 0x00, 0x00, /* resource type */
};
const size_t key_handle_offset = 10;
const size_t resource_type_offset = 14;
uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
size_t response_length = sizeof(response);
uint32_t err;
if (pack_byte_string(buf, sizeof(buf), "sdd",
0, command, sizeof(command),
key_handle_offset, key_handle,
resource_type_offset, resource_type))
return TPM_LIB_ERROR;
err = tpm_sendrecv_command(buf, response, &response_length);
if (err)
return err;
return 0;
}
#endif /* CONFIG_TPM_FLUSH_RESOURCES */
#ifdef CONFIG_TPM_AUTH_SESSIONS
/**

View File

@ -142,8 +142,12 @@ ifdef CONFIG_SYS_U_BOOT_OFFS
HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS)
endif
ifneq ($(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),)
HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE
endif
# MXSImage needs LibSSL
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),)
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),)
HOSTLOADLIBES_mkimage += \
$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")

File diff suppressed because it is too large Load Diff

View File

@ -113,6 +113,43 @@ struct opt_hdr_v1 {
char data[0];
};
/*
* Public Key data in DER format
*/
struct pubkey_der_v1 {
uint8_t key[524];
};
/*
* Signature (RSA 2048)
*/
struct sig_v1 {
uint8_t sig[256];
};
/*
* Structure of secure header (Armada 38x)
*/
struct secure_hdr_v1 {
uint8_t headertype; /* 0x0 */
uint8_t headersz_msb; /* 0x1 */
uint16_t headersz_lsb; /* 0x2 - 0x3 */
uint32_t reserved1; /* 0x4 - 0x7 */
struct pubkey_der_v1 kak; /* 0x8 - 0x213 */
uint8_t jtag_delay; /* 0x214 */
uint8_t reserved2; /* 0x215 */
uint16_t reserved3; /* 0x216 - 0x217 */
uint32_t boxid; /* 0x218 - 0x21B */
uint32_t flashid; /* 0x21C - 0x21F */
struct sig_v1 hdrsig; /* 0x220 - 0x31F */
struct sig_v1 imgsig; /* 0x320 - 0x41F */
struct pubkey_der_v1 csk[16]; /* 0x420 - 0x24DF */
struct sig_v1 csksig; /* 0x24E0 - 0x25DF */
uint8_t next; /* 0x25E0 */
uint8_t reserved4; /* 0x25E1 */
uint16_t reserved5; /* 0x25E2 - 0x25E3 */
};
/*
* Various values for the opt_hdr_v1->headertype field, describing the
* different types of optional headers. The "secure" header contains