Pull request for efi-2022-01-rc1-2

doc:
 	Remove obsolete PPC4XX references
 
 UEFI:
 	Implement missing TCG2 measurements
 	Code clean up
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmF4eZ8ACgkQxIHbvCwF
 GsSDRxAAlujYTep5xp0/yzSvUvS5ocJBstgw0YuO4GY1RtXN9Zgdd1PeETdEh7HW
 HKNOrx3Bk1LlyLeObyKX6Dq3p4PkYX8q4ciaWkTqPoId2LKeXYJGxABled6EW8OJ
 68/smhQOoivQPuDTZsUCJXdsRnnoxAhO5S03JEgIZKeusOJjZQ5QVS0a91ovOllB
 sjMcpm4HDO0hkEo59ExP2unlRrBuB7L0VwA+SxvXB1e8vruWxye8i5Fw/hN9g73h
 Atrl9/Mbn1ppWqHgOMaMawxPhuceZjINpRJXIZ5H5m4bgwYrjk9HFJGV3C1eOo5a
 Vdc8/I1X5GXetn6kFae7vSJhU9QgHK1QsXjObs/ksOwS0+K4QRFc1X6aMkdO8QPI
 3EfVUaeedDdzrQdtATu9L9a6dVuE79abNNevUglmZrvKWqgMIl61M1Ffl7IWuCJo
 t6YyCZmBvt4rNh1/UEbkL9d7y5lkoCJafe9EMYwZk0zfPamw08bB8KWDIJrm0P0w
 fnSdEDQdnHvFfZ//th/u7Q6zpfN9waxZ93mMvfBkmjCi8aa0GLMIStcYcOoJm+Z6
 QdzaP5XPQ4gC2A7lqSOPwExUgvcfx0y6AuIoTdusqU7w5+obqnc+e4FN7UFxzr5K
 ZCf6+8JO3rbD9ptWpCEDFpFdMbq32MwGTKM2Jy7kL1nzGKcNdPE=
 =LkPN
 -----END PGP SIGNATURE-----

Merge tag 'efi-2022-01-rc1-2' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-01-rc1-2

doc:
	Remove obsolete PPC4XX references

UEFI:
	Implement missing TCG2 measurements
	Code clean up

# gpg: Signature made Tue 26 Oct 2021 05:56:47 PM EDT
# gpg:                using RSA key 6DC4F9C71F29A6FA06B76D33C481DBBC2C051AC4
# gpg: Good signature from "Heinrich Schuchardt <xypron.glpk@gmx.de>" [unknown]
# gpg:                 aka "[jpeg image of size 1389]" [unknown]
# Primary key fingerprint: 6DC4 F9C7 1F29 A6FA 06B7  6D33 C481 DBBC 2C05 1AC4
This commit is contained in:
Tom Rini 2021-10-26 18:42:26 -04:00
commit 670d657dfb
23 changed files with 715 additions and 388 deletions

View File

@ -24,6 +24,7 @@ Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
Dirk Behme <dirk.behme@googlemail.com>
Fabio Estevam <fabio.estevam@nxp.com>
Heinrich Schuchardt <xypron.glpk@gmx.de> <heinrich.schuchardt@canonical.com>
Jagan Teki <402jagan@gmail.com>
Jagan Teki <jaganna@gmail.com>
Jagan Teki <jaganna@xilinx.com>

View File

@ -2,8 +2,6 @@ BEDBUG Support for U-Boot
--------------------------
These changes implement the bedbug (emBEDded deBUGger) debugger in U-Boot.
A specific implementation is made for the AMCC 405 processor but other flavors
can be easily implemented.
#####################
### Modifications ###
@ -12,25 +10,9 @@ can be easily implemented.
./common/Makefile
Included cmd_bedbug.c and bedbug.c in the Makefile.
./common/command.c
Added bedbug commands to command table.
./common/board.c
Added call to initialize debugger on startup.
./arch/powerpc/cpu/ppc4xx/Makefile
Added bedbug_405.c to the Makefile.
./arch/powerpc/cpu/ppc4xx/start.S
Added code to handle the debug exception (0x2000) on the 405.
Also added code to handle critical exceptions since the debug
is treated as critical on the 405.
./arch/powerpc/cpu/ppc4xx/traps.c
Added more detailed output for the program exception to tell
if it is an illegal instruction, privileged instruction or
a trap. Also added debug trap handler.
./include/ppc_asm.tmpl
Added code to handle critical exceptions
@ -51,10 +33,6 @@ can be easily implemented.
hardware breakpoints and stepping through code. These
routines are common to all PowerPC processors.
./arch/powerpc/cpu/ppc4xx/bedbug_405.c
AMCC PPC405 specific debugger routines.
Bedbug support for the MPC860
-----------------------------

View File

@ -1,22 +0,0 @@
This file contains status information for the port of U-Boot to the
Motorola mpc74xx series of CPUs.
Author: Josh Huber <huber@mclx.com>
Mission Critical Linux, Inc.
Currently the support for these CPUs is pretty minimal, but enough to
get things going. (much like the support for the Galileo Eval Board)
There is a framework in place to enable the L2 cache, and to program
the BATs. Currently, there are still problems with the code which
sets up the L2 cache, so it's not enabled. (IMHO, it shouldn't be
anyway). Additionally, there is support for enabling the MMU, which
we also don't do. The BATs are programmed just for the benefit of
jumping into Linux in a sane configuration.
Most of the code was based on other cpus supported by U-Boot.
If you find any errors in the CPU setup code, please send us a note.
Thanks,
Josh

View File

@ -277,6 +277,130 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE`
[1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html
Enabling UEFI Capsule Update feature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support has been added for the UEFI capsule update feature which
enables updating the U-Boot image using the UEFI firmware management
protocol (FMP). The capsules are not passed to the firmware through
the UpdateCapsule runtime service. Instead, capsule-on-disk
functionality is used for fetching the capsule from the EFI System
Partition (ESP) by placing the capsule file under the
\EFI\UpdateCapsule directory.
The directory \EFI\UpdateCapsule is checked for capsules only within the
EFI system partition on the device specified in the active boot option
determined by reference to BootNext variable or BootOrder variable processing.
The active Boot Variable is the variable with highest priority BootNext or
within BootOrder that refers to a device found to be present. Boot variables
in BootOrder but referring to devices not present are ignored when determining
active boot variable.
Before starting a capsule update make sure your capsules are installed in the
correct ESP partition or set BootNext.
Performing the update
*********************
Since U-boot doesn't currently support SetVariable at runtime there's a Kconfig
option (CONFIG_EFI_IGNORE_OSINDICATIONS) to disable the OsIndications variable
check. If that option is enabled just copy your capsule to \EFI\UpdateCapsule.
If that option is disabled, you'll need to set the OsIndications variable with::
=> setenv -e -nv -bs -rt -v OsIndications =0x04
Finally, the capsule update can be initiated either by rebooting the board,
which is the preferred method, or by issuing the following command::
=> efidebug capsule disk-update
**The efidebug command is should only be used during debugging/development.**
Enabling Capsule Authentication
*******************************
The UEFI specification defines a way of authenticating the capsule to
be updated by verifying the capsule signature. The capsule signature
is computed and prepended to the capsule payload at the time of
capsule generation. This signature is then verified by using the
public key stored as part of the X509 certificate. This certificate is
in the form of an efi signature list (esl) file, which is embedded as
part of U-Boot.
The capsule authentication feature can be enabled through the
following config, in addition to the configs listed above for capsule
update::
CONFIG_EFI_CAPSULE_AUTHENTICATE=y
CONFIG_EFI_CAPSULE_KEY_PATH=<path to .esl cert>
The public and private keys used for the signing process are generated
and used by the steps highlighted below::
1. Install utility commands on your host
* OPENSSL
* efitools
2. Create signing keys and certificate files on your host
$ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \
-keyout CRT.key -out CRT.crt -nodes -days 365
$ cert-to-efi-sig-list CRT.crt CRT.esl
$ openssl x509 -in CRT.crt -out CRT.cer -outform DER
$ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem
$ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt
$ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem
The capsule file can be generated by using the GenerateCapsule.py
script in EDKII::
$ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
<capsule_file_name> --monotonic-count <val> --fw-version \
<val> --lsv <val> --guid \
e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
--update-image-index <val> --signer-private-cert \
/path/to/CRT.pem --trusted-public-cert \
/path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
<u-boot.bin>
Place the capsule generated in the above step on the EFI System
Partition under the EFI/UpdateCapsule directory
Testing on QEMU
***************
Currently, support has been added on the QEMU ARM64 virt platform for
updating the U-Boot binary as a raw image when the platform is booted
in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this
configuration, the QEMU platform needs to be booted with
'secure=off'. The U-Boot binary placed on the first bank of the NOR
flash at offset 0x0. The U-Boot environment is placed on the second
NOR flash bank at offset 0x4000000.
The capsule update feature is enabled with the following configuration
settings::
CONFIG_MTD=y
CONFIG_FLASH_CFI_MTD=y
CONFIG_CMD_MTDPARTS=y
CONFIG_CMD_DFU=y
CONFIG_DFU_MTD=y
CONFIG_PCI_INIT_R=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
CONFIG_EFI_CAPSULE_FIRMWARE=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
In addition, the following config needs to be disabled(QEMU ARM specific)::
CONFIG_TFABOOT
The capsule file can be generated by using the tools/mkeficapsule::
$ mkeficapsule --raw <u-boot.bin> --index 1 <capsule_file_name>
Executing the boot manager
~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -45,6 +45,9 @@ enum if_type {
#define BLK_PRD_SIZE 20
#define BLK_REV_SIZE 8
#define PART_FORMAT_PCAT 0x1
#define PART_FORMAT_GPT 0x2
/*
* Identifies the partition table type (ie. MBR vs GPT GUID) signature
*/

View File

@ -120,7 +120,7 @@ struct efi_boot_services {
struct efi_device_path **device_path,
efi_handle_t *device);
efi_status_t (EFIAPI *install_configuration_table)(
efi_guid_t *guid, void *table);
const efi_guid_t *guid, void *table);
efi_status_t (EFIAPI *load_image)(bool boot_policiy,
efi_handle_t parent_image,

View File

@ -308,6 +308,8 @@ extern const efi_guid_t efi_guid_capsule_report;
extern const efi_guid_t efi_guid_firmware_management_protocol;
/* GUID for the ESRT */
extern const efi_guid_t efi_esrt_guid;
/* GUID of the SMBIOS table */
extern const efi_guid_t smbios_guid;
extern char __efi_runtime_start[], __efi_runtime_stop[];
extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[];
@ -501,7 +503,7 @@ efi_status_t efi_init_variables(void);
void efi_variables_boot_exit_notify(void);
efi_status_t efi_tcg2_notify_exit_boot_services_failed(void);
/* Measure efi application invocation */
efi_status_t efi_tcg2_measure_efi_app_invocation(void);
efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *handle);
/* Measure efi application exit */
efi_status_t efi_tcg2_measure_efi_app_exit(void);
/* Called by bootefi to initialize root node */
@ -818,7 +820,7 @@ efi_status_t EFIAPI efi_query_variable_info(
u64 *remaining_variable_storage_size,
u64 *maximum_variable_size);
void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
/*
* See section 3.1.3 in the v2.7 UEFI spec for more details on
@ -845,6 +847,7 @@ struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
const efi_guid_t *guid);
struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
const struct efi_device_path *dp2);
struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path);
efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
efi_uintn_t *size);
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);

View File

@ -210,6 +210,33 @@ struct efi_tcg2_uefi_variable_data {
u8 variable_data[1];
};
/**
* struct tdUEFI_HANDOFF_TABLE_POINTERS2 - event log structure of SMBOIS tables
* @table_description_size: size of table description
* @table_description: table description
* @number_of_tables: number of uefi configuration table
* @table_entry: uefi configuration table entry
*/
#define SMBIOS_HANDOFF_TABLE_DESC "SmbiosTable"
struct smbios_handoff_table_pointers2 {
u8 table_description_size;
u8 table_description[sizeof(SMBIOS_HANDOFF_TABLE_DESC)];
u64 number_of_tables;
struct efi_configuration_table table_entry[];
} __packed;
/**
* struct tdUEFI_GPT_DATA - event log structure of industry standard tables
* @uefi_partition_header: gpt partition header
* @number_of_partitions: the number of partition
* @partitions: partition entries
*/
struct efi_gpt_data {
gpt_header uefi_partition_header;
u64 number_of_partitions;
gpt_entry partitions[];
} __packed;
struct efi_tcg2_protocol {
efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this,
struct efi_tcg2_boot_service_capability *capability);

View File

@ -32,7 +32,8 @@ enum efi_auth_var_type {
* @timep: authentication time (seconds since start of epoch)
* Return: status code
*/
efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
efi_status_t efi_get_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size,
void *data, u64 *timep);
@ -47,7 +48,8 @@ efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
* @ro_check: check the read only read only bit in attributes
* Return: status code
*/
efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data, bool ro_check);
@ -224,7 +226,7 @@ void efi_var_mem_del(struct efi_var_entry *var);
* @time: time of authentication (as seconds since start of epoch)
* Result: status code
*/
efi_status_t efi_var_mem_ins(u16 *variable_name,
efi_status_t efi_var_mem_ins(const u16 *variable_name,
const efi_guid_t *vendor, u32 attributes,
const efi_uintn_t size1, const void *data1,
const efi_uintn_t size2, const void *data2,
@ -251,7 +253,16 @@ efi_status_t efi_init_secure_state(void);
* @guid: guid of UEFI variable
* Return: identifier for authentication related variables
*/
enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid);
enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
const efi_guid_t *guid);
/**
* efi_auth_var_get_guid() - get the predefined GUID for a variable name
*
* @name: name of UEFI variable
* Return: guid of UEFI variable
*/
const efi_guid_t *efi_auth_var_get_guid(const u16 *name);
/**
* efi_get_next_variable_name_mem() - Runtime common code across efi variable
@ -280,8 +291,9 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_na
* Return: status code
*/
efi_status_t __efi_runtime
efi_get_variable_mem(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes,
efi_uintn_t *data_size, void *data, u64 *timep);
efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep);
/**
* efi_get_variable_runtime() - runtime implementation of GetVariable()

View File

@ -260,9 +260,9 @@ const struct smbios_header *smbios_header(const struct smbios_entry *entry, int
*
* @header: pointer to struct smbios_header
* @index: string index
* @return: NULL or a valid const char pointer
* @return: NULL or a valid char pointer
*/
const char *smbios_string(const struct smbios_header *header, int index);
char *smbios_string(const struct smbios_header *header, int index);
/**
* smbios_update_version() - Update the version string
@ -292,4 +292,17 @@ int smbios_update_version(const char *version);
*/
int smbios_update_version_full(void *smbios_tab, const char *version);
/**
* smbios_prepare_measurement() - Update smbios table for the measurement
*
* TCG specification requires to measure static configuration information.
* This function clear the device dependent parameters such as
* serial number for the measurement.
*
* @entry: pointer to a struct smbios_entry
* @header: pointer to a struct smbios_header
*/
void smbios_prepare_measurement(const struct smbios_entry *entry,
struct smbios_header *header);
#endif /* _SMBIOS_H_ */

View File

@ -312,6 +312,7 @@ config EFI_TCG2_PROTOCOL
select SHA384
select SHA512
select HASH
select SMBIOS_PARSER
help
Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
of the platform.

View File

@ -86,6 +86,8 @@ const efi_guid_t efi_guid_event_group_reset_system =
/* GUIDs of the Load File and Load File2 protocols */
const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID;
const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID;
/* GUID of the SMBIOS table */
const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t controller_handle,
@ -1690,8 +1692,9 @@ out:
*
* Return: status code
*/
static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
void *table)
static efi_status_t
EFIAPI efi_install_configuration_table_ext(const efi_guid_t *guid,
void *table)
{
EFI_ENTRY("%pUl, %p", guid, table);
return EFI_EXIT(efi_install_configuration_table(guid, table));
@ -3001,7 +3004,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
ret = efi_tcg2_measure_efi_app_invocation();
ret = efi_tcg2_measure_efi_app_invocation(image_obj);
if (ret != EFI_SUCCESS) {
log_warning("tcg2 measurement fails(0x%lx)\n",
ret);

View File

@ -11,15 +11,20 @@
#include <common.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <env.h>
#include <fdtdec.h>
#include <fs.h>
#include <malloc.h>
#include <mapmem.h>
#include <sort.h>
#include <asm/global_data.h>
#include <crypto/pkcs7.h>
#include <crypto/pkcs7_parser.h>
#include <linux/err.h>
DECLARE_GLOBAL_DATA_PTR;
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
static const efi_guid_t efi_guid_firmware_management_capsule_id =
EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
@ -251,6 +256,37 @@ out:
}
#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
int __weak efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
{
const void *fdt_blob = gd->fdt_blob;
const void *blob;
const char *cnode_name = "capsule-key";
const char *snode_name = "signature";
int sig_node;
int len;
sig_node = fdt_subnode_offset(fdt_blob, 0, snode_name);
if (sig_node < 0) {
log_err("Unable to get signature node offset\n");
return -FDT_ERR_NOTFOUND;
}
blob = fdt_getprop(fdt_blob, sig_node, cnode_name, &len);
if (!blob || len < 0) {
log_err("Unable to get capsule-key value\n");
*pkey = NULL;
*pkey_len = 0;
return -FDT_ERR_NOTFOUND;
}
*pkey = (void *)blob;
*pkey_len = len;
return 0;
}
efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
void **image, efi_uintn_t *image_size)

View File

@ -1239,3 +1239,30 @@ efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
return NULL;
}
/**
* search_gpt_dp_node() - search gpt device path node
*
* @device_path: device path
*
* Return: pointer to the gpt device path node
*/
struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
{
struct efi_device_path *dp = device_path;
while (dp) {
if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
struct efi_device_path_hard_drive_path *hd_dp =
(struct efi_device_path_hard_drive_path *)dp;
if (hd_dp->partmap_type == PART_FORMAT_GPT &&
hd_dp->signature_type == SIG_TYPE_GUID)
return dp;
}
dp = efi_dp_next(dp);
}
return NULL;
}

View File

@ -7,6 +7,7 @@
#include <common.h>
#include <charset.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <image.h>
#include <hexdump.h>
#include <malloc.h>
@ -740,44 +741,15 @@ err:
*/
struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
{
struct efi_signature_store *sigstore = NULL;
const efi_guid_t *vendor;
void *db;
efi_uintn_t db_size;
efi_status_t ret;
if (!u16_strcmp(name, L"PK") || !u16_strcmp(name, L"KEK")) {
vendor = &efi_global_variable_guid;
} else if (!u16_strcmp(name, L"db") || !u16_strcmp(name, L"dbx")) {
vendor = &efi_guid_image_security_database;
} else {
EFI_PRINT("unknown signature database, %ls\n", name);
return NULL;
}
/* retrieve variable data */
db_size = 0;
ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, NULL));
if (ret == EFI_NOT_FOUND) {
EFI_PRINT("variable, %ls, not found\n", name);
sigstore = calloc(sizeof(*sigstore), 1);
return sigstore;
} else if (ret != EFI_BUFFER_TOO_SMALL) {
EFI_PRINT("Getting variable, %ls, failed\n", name);
return NULL;
}
db = malloc(db_size);
vendor = efi_auth_var_get_guid(name);
db = efi_get_var(name, vendor, &db_size);
if (!db) {
EFI_PRINT("Out of memory\n");
return NULL;
}
ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
if (ret != EFI_SUCCESS) {
EFI_PRINT("Getting variable, %ls, failed\n", name);
free(db);
return NULL;
EFI_PRINT("variable, %ls, not found\n", name);
return calloc(sizeof(struct efi_signature_store), 1);
}
return efi_build_signature_store(db, db_size);

View File

@ -13,8 +13,6 @@
#include <mapmem.h>
#include <smbios.h>
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
/*
* Install the SMBIOS table as a configuration table.
*

View File

@ -11,9 +11,11 @@
#include <common.h>
#include <dm.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <efi_tcg2.h>
#include <log.h>
#include <malloc.h>
#include <smbios.h>
#include <version_string.h>
#include <tpm-v2.h>
#include <u-boot/hash-checksum.h>
@ -80,16 +82,21 @@ static const struct digest_info hash_algo_list[] = {
};
struct variable_info {
u16 *name;
const efi_guid_t *guid;
const u16 *name;
bool accept_empty;
u32 pcr_index;
};
static struct variable_info secure_variables[] = {
{L"SecureBoot", &efi_global_variable_guid},
{L"PK", &efi_global_variable_guid},
{L"KEK", &efi_global_variable_guid},
{L"db", &efi_guid_image_security_database},
{L"dbx", &efi_guid_image_security_database},
{u"SecureBoot", true, 7},
{u"PK", true, 7},
{u"KEK", true, 7},
{u"db", true, 7},
{u"dbx", true, 7},
{u"dbt", false, 7},
{u"dbr", false, 7},
{u"DeployedMode", false, 1},
{u"AuditMode", false, 1},
};
#define MAX_HASH_COUNT ARRAY_SIZE(hash_algo_list)
@ -1366,7 +1373,7 @@ static efi_status_t efi_append_scrtm_version(struct udevice *dev)
* Return: status code
*/
static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,
u32 event_type, u16 *var_name,
u32 event_type, const u16 *var_name,
const efi_guid_t *guid,
efi_uintn_t data_size, u8 *data)
{
@ -1456,17 +1463,233 @@ error:
return ret;
}
/**
* tcg2_measure_smbios() - measure smbios table
*
* @dev: TPM device
* @entry: pointer to the smbios_entry structure
*
* Return: status code
*/
static efi_status_t
tcg2_measure_smbios(struct udevice *dev,
const struct smbios_entry *entry)
{
efi_status_t ret;
struct smbios_header *smbios_copy;
struct smbios_handoff_table_pointers2 *event = NULL;
u32 event_size;
/*
* TCG PC Client PFP Spec says
* "SMBIOS structures that contain static configuration information
* (e.g. Platform Manufacturer Enterprise Number assigned by IANA,
* platform model number, Vendor and Device IDs for each SMBIOS table)
* that is relevant to the security of the platform MUST be measured".
* Device dependent parameters such as serial number are cleared to
* zero or spaces for the measurement.
*/
event_size = sizeof(struct smbios_handoff_table_pointers2) +
FIELD_SIZEOF(struct efi_configuration_table, guid) +
entry->struct_table_length;
event = calloc(1, event_size);
if (!event) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
event->table_description_size = sizeof(SMBIOS_HANDOFF_TABLE_DESC);
memcpy(event->table_description, SMBIOS_HANDOFF_TABLE_DESC,
sizeof(SMBIOS_HANDOFF_TABLE_DESC));
put_unaligned_le64(1, &event->number_of_tables);
guidcpy(&event->table_entry[0].guid, &smbios_guid);
smbios_copy = (struct smbios_header *)((uintptr_t)&event->table_entry[0].table);
memcpy(&event->table_entry[0].table,
(void *)((uintptr_t)entry->struct_table_address),
entry->struct_table_length);
smbios_prepare_measurement(entry, smbios_copy);
ret = tcg2_measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size,
(u8 *)event);
if (ret != EFI_SUCCESS)
goto out;
out:
free(event);
return ret;
}
/**
* find_smbios_table() - find smbios table
*
* Return: pointer to the smbios table
*/
static void *find_smbios_table(void)
{
u32 i;
for (i = 0; i < systab.nr_tables; i++) {
if (!guidcmp(&smbios_guid, &systab.tables[i].guid))
return systab.tables[i].table;
}
return NULL;
}
/**
* tcg2_measure_gpt_table() - measure gpt table
*
* @dev: TPM device
* @loaded_image: handle to the loaded image
*
* Return: status code
*/
static efi_status_t
tcg2_measure_gpt_data(struct udevice *dev,
struct efi_loaded_image_obj *loaded_image)
{
efi_status_t ret;
efi_handle_t handle;
struct efi_handler *dp_handler;
struct efi_device_path *orig_device_path;
struct efi_device_path *device_path;
struct efi_device_path *dp;
struct efi_block_io *block_io;
struct efi_gpt_data *event = NULL;
efi_guid_t null_guid = NULL_GUID;
gpt_header *gpt_h;
gpt_entry *entry = NULL;
gpt_entry *gpt_e;
u32 num_of_valid_entry = 0;
u32 event_size;
u32 i;
u32 total_gpt_entry_size;
ret = efi_search_protocol(&loaded_image->header,
&efi_guid_loaded_image_device_path,
&dp_handler);
if (ret != EFI_SUCCESS)
return ret;
orig_device_path = dp_handler->protocol_interface;
if (!orig_device_path) /* no device path, skip GPT measurement */
return EFI_SUCCESS;
device_path = efi_dp_dup(orig_device_path);
if (!device_path)
return EFI_OUT_OF_RESOURCES;
dp = search_gpt_dp_node(device_path);
if (!dp) {
/* no GPT device path node found, skip GPT measurement */
ret = EFI_SUCCESS;
goto out1;
}
/* read GPT header */
dp->type = DEVICE_PATH_TYPE_END;
dp->sub_type = DEVICE_PATH_SUB_TYPE_END;
dp = device_path;
ret = EFI_CALL(systab.boottime->locate_device_path(&efi_block_io_guid,
&dp, &handle));
if (ret != EFI_SUCCESS)
goto out1;
ret = EFI_CALL(efi_handle_protocol(handle,
&efi_block_io_guid, (void **)&block_io));
if (ret != EFI_SUCCESS)
goto out1;
gpt_h = memalign(block_io->media->io_align, block_io->media->block_size);
if (!gpt_h) {
ret = EFI_OUT_OF_RESOURCES;
goto out2;
}
ret = block_io->read_blocks(block_io, block_io->media->media_id, 1,
block_io->media->block_size, gpt_h);
if (ret != EFI_SUCCESS)
goto out2;
/* read GPT entry */
total_gpt_entry_size = gpt_h->num_partition_entries *
gpt_h->sizeof_partition_entry;
entry = memalign(block_io->media->io_align, total_gpt_entry_size);
if (!entry) {
ret = EFI_OUT_OF_RESOURCES;
goto out2;
}
ret = block_io->read_blocks(block_io, block_io->media->media_id,
gpt_h->partition_entry_lba,
total_gpt_entry_size, entry);
if (ret != EFI_SUCCESS)
goto out2;
/* count valid GPT entry */
gpt_e = entry;
for (i = 0; i < gpt_h->num_partition_entries; i++) {
if (guidcmp(&null_guid, &gpt_e->partition_type_guid))
num_of_valid_entry++;
gpt_e = (gpt_entry *)((u8 *)gpt_e + gpt_h->sizeof_partition_entry);
}
/* prepare event data for measurement */
event_size = sizeof(struct efi_gpt_data) +
(num_of_valid_entry * gpt_h->sizeof_partition_entry);
event = calloc(1, event_size);
if (!event) {
ret = EFI_OUT_OF_RESOURCES;
goto out2;
}
memcpy(event, gpt_h, sizeof(gpt_header));
put_unaligned_le64(num_of_valid_entry, &event->number_of_partitions);
/* copy valid GPT entry */
gpt_e = entry;
num_of_valid_entry = 0;
for (i = 0; i < gpt_h->num_partition_entries; i++) {
if (guidcmp(&null_guid, &gpt_e->partition_type_guid)) {
memcpy((u8 *)event->partitions +
(num_of_valid_entry * gpt_h->sizeof_partition_entry),
gpt_e, gpt_h->sizeof_partition_entry);
num_of_valid_entry++;
}
gpt_e = (gpt_entry *)((u8 *)gpt_e + gpt_h->sizeof_partition_entry);
}
ret = tcg2_measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 *)event);
if (ret != EFI_SUCCESS)
goto out2;
out2:
EFI_CALL(efi_close_protocol((efi_handle_t)block_io, &efi_block_io_guid,
NULL, NULL));
free(gpt_h);
free(entry);
free(event);
out1:
efi_free_pool(device_path);
return ret;
}
/**
* efi_tcg2_measure_efi_app_invocation() - measure efi app invocation
*
* Return: status code
*/
efi_status_t efi_tcg2_measure_efi_app_invocation(void)
efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *handle)
{
efi_status_t ret;
u32 pcr_index;
struct udevice *dev;
u32 event = 0;
struct smbios_entry *entry;
if (tcg2_efi_app_invoked)
return EFI_SUCCESS;
@ -1485,6 +1708,17 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(void)
if (ret != EFI_SUCCESS)
goto out;
entry = (struct smbios_entry *)find_smbios_table();
if (entry) {
ret = tcg2_measure_smbios(dev, entry);
if (ret != EFI_SUCCESS)
goto out;
}
ret = tcg2_measure_gpt_data(dev, handle);
if (ret != EFI_SUCCESS)
goto out;
for (pcr_index = 0; pcr_index <= 7; pcr_index++) {
ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,
sizeof(event), (u8 *)&event);
@ -1591,56 +1825,40 @@ static efi_status_t tcg2_measure_secure_boot_variable(struct udevice *dev)
efi_uintn_t data_size;
u32 count, i;
efi_status_t ret;
u8 deployed_mode;
efi_uintn_t size;
u32 deployed_audit_pcr_index = 1;
size = sizeof(deployed_mode);
ret = efi_get_variable_int(u"DeployedMode", &efi_global_variable_guid,
NULL, &size, &deployed_mode, NULL);
if (ret != EFI_SUCCESS || !deployed_mode)
deployed_audit_pcr_index = 7;
count = ARRAY_SIZE(secure_variables);
for (i = 0; i < count; i++) {
/*
* According to the TCG2 PC Client PFP spec, "SecureBoot",
* "PK", "KEK", "db" and "dbx" variables must be measured
* even if they are empty.
*/
data = efi_get_var(secure_variables[i].name,
secure_variables[i].guid,
&data_size);
const efi_guid_t *guid;
ret = tcg2_measure_variable(dev, 7,
guid = efi_auth_var_get_guid(secure_variables[i].name);
data = efi_get_var(secure_variables[i].name, guid, &data_size);
if (!data && !secure_variables[i].accept_empty)
continue;
if (u16_strcmp(u"DeployedMode", secure_variables[i].name))
secure_variables[i].pcr_index = deployed_audit_pcr_index;
if (u16_strcmp(u"AuditMode", secure_variables[i].name))
secure_variables[i].pcr_index = deployed_audit_pcr_index;
ret = tcg2_measure_variable(dev, secure_variables[i].pcr_index,
EV_EFI_VARIABLE_DRIVER_CONFIG,
secure_variables[i].name,
secure_variables[i].guid,
secure_variables[i].name, guid,
data_size, data);
free(data);
if (ret != EFI_SUCCESS)
goto error;
}
/*
* TCG2 PC Client PFP spec says "dbt" and "dbr" are
* measured if present and not empty.
*/
data = efi_get_var(L"dbt",
&efi_guid_image_security_database,
&data_size);
if (data) {
ret = tcg2_measure_variable(dev, 7,
EV_EFI_VARIABLE_DRIVER_CONFIG,
L"dbt",
&efi_guid_image_security_database,
data_size, data);
free(data);
}
data = efi_get_var(L"dbr",
&efi_guid_image_security_database,
&data_size);
if (data) {
ret = tcg2_measure_variable(dev, 7,
EV_EFI_VARIABLE_DRIVER_CONFIG,
L"dbr",
&efi_guid_image_security_database,
data_size, data);
free(data);
}
error:
return ret;
}

View File

@ -374,7 +374,8 @@ bool efi_secure_boot_enabled(void)
return efi_secure_boot;
}
enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
const efi_guid_t *guid)
{
for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
if (!u16_strcmp(name, name_type[i].name) &&
@ -384,6 +385,15 @@ enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
return EFI_AUTH_VAR_NONE;
}
const efi_guid_t *efi_auth_var_get_guid(const u16 *name)
{
for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
if (!u16_strcmp(name, name_type[i].name))
return name_type[i].guid;
}
return &efi_global_variable_guid;
}
/**
* efi_get_var() - read value of an EFI variable
*
@ -393,7 +403,7 @@ enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
*
* Return: buffer with variable data or NULL
*/
void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
{
efi_status_t ret;
void *buf = NULL;

View File

@ -134,7 +134,7 @@ void __efi_runtime efi_var_mem_del(struct efi_var_entry *var)
}
efi_status_t __efi_runtime efi_var_mem_ins(
u16 *variable_name,
const u16 *variable_name,
const efi_guid_t *vendor, u32 attributes,
const efi_uintn_t size1, const void *data1,
const efi_uintn_t size2, const void *data2,
@ -274,8 +274,9 @@ efi_status_t efi_var_mem_init(void)
}
efi_status_t __efi_runtime
efi_get_variable_mem(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes,
efi_uintn_t *data_size, void *data, u64 *timep)
efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep)
{
efi_uintn_t old_size;
struct efi_var_entry *var;

View File

@ -45,7 +45,7 @@
*
* Return: status code
*/
static efi_status_t efi_variable_authenticate(u16 *variable,
static efi_status_t efi_variable_authenticate(const u16 *variable,
const efi_guid_t *vendor,
efi_uintn_t *data_size,
const void **data, u32 given_attr,
@ -194,7 +194,7 @@ err:
return ret;
}
#else
static efi_status_t efi_variable_authenticate(u16 *variable,
static efi_status_t efi_variable_authenticate(const u16 *variable,
const efi_guid_t *vendor,
efi_uintn_t *data_size,
const void **data, u32 given_attr,
@ -205,7 +205,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
#endif /* CONFIG_EFI_SECURE_BOOT */
efi_status_t __efi_runtime
efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
efi_get_variable_int(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep)
{
@ -219,7 +219,8 @@ efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
return efi_get_next_variable_name_mem(variable_name_size, variable_name, vendor);
}
efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data, bool ro_check)
{

View File

@ -284,7 +284,8 @@ out:
* StMM can store internal attributes and properties for variables, i.e enabling
* R/O variables
*/
static efi_status_t set_property_int(u16 *variable_name, efi_uintn_t name_size,
static efi_status_t set_property_int(const u16 *variable_name,
efi_uintn_t name_size,
const efi_guid_t *vendor,
struct var_check_property *var_property)
{
@ -317,7 +318,8 @@ out:
return ret;
}
static efi_status_t get_property_int(u16 *variable_name, efi_uintn_t name_size,
static efi_status_t get_property_int(const u16 *variable_name,
efi_uintn_t name_size,
const efi_guid_t *vendor,
struct var_check_property *var_property)
{
@ -361,7 +363,8 @@ out:
return ret;
}
efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
efi_status_t efi_get_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size,
void *data, u64 *timep)
{
@ -502,9 +505,10 @@ out:
return ret;
}
efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data, bool ro_check)
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor, u32 attributes,
efi_uintn_t data_size, const void *data,
bool ro_check)
{
efi_status_t ret, alt_ret = EFI_SUCCESS;
struct var_check_property var_property;

View File

@ -39,10 +39,8 @@ const struct smbios_entry *smbios_entry(u64 address, u32 size)
return entry;
}
static const struct smbios_header *next_header(const struct smbios_header *curr)
static u8 *find_next_header(u8 *pos)
{
u8 *pos = ((u8 *)curr) + curr->length;
/* search for _double_ NULL bytes */
while (!((*pos == 0) && (*(pos + 1) == 0)))
pos++;
@ -50,13 +48,27 @@ static const struct smbios_header *next_header(const struct smbios_header *curr)
/* step behind the double NULL bytes */
pos += 2;
return (struct smbios_header *)pos;
return pos;
}
static struct smbios_header *get_next_header(struct smbios_header *curr)
{
u8 *pos = ((u8 *)curr) + curr->length;
return (struct smbios_header *)find_next_header(pos);
}
static const struct smbios_header *next_header(const struct smbios_header *curr)
{
u8 *pos = ((u8 *)curr) + curr->length;
return (struct smbios_header *)find_next_header(pos);
}
const struct smbios_header *smbios_header(const struct smbios_entry *entry, int type)
{
const unsigned int num_header = entry->struct_count;
const struct smbios_header *header = (struct smbios_header *)entry->struct_table_address;
const struct smbios_header *header = (struct smbios_header *)((uintptr_t)entry->struct_table_address);
for (unsigned int i = 0; i < num_header; i++) {
if (header->type == type)
@ -68,8 +80,8 @@ const struct smbios_header *smbios_header(const struct smbios_entry *entry, int
return NULL;
}
static const char *string_from_smbios_table(const struct smbios_header *header,
int idx)
static char *string_from_smbios_table(const struct smbios_header *header,
int idx)
{
unsigned int i = 1;
u8 *pos;
@ -86,10 +98,10 @@ static const char *string_from_smbios_table(const struct smbios_header *header,
pos++;
}
return (const char *)pos;
return (char *)pos;
}
const char *smbios_string(const struct smbios_header *header, int index)
char *smbios_string(const struct smbios_header *header, int index)
{
if (!header)
return NULL;
@ -109,7 +121,7 @@ int smbios_update_version_full(void *smbios_tab, const char *version)
if (!hdr)
return log_msg_ret("tab", -ENOENT);
bios = (struct smbios_type0 *)hdr;
ptr = (char *)smbios_string(hdr, bios->bios_ver);
ptr = smbios_string(hdr, bios->bios_ver);
if (!ptr)
return log_msg_ret("str", -ENOMEDIUM);
@ -132,3 +144,123 @@ int smbios_update_version_full(void *smbios_tab, const char *version)
return 0;
}
struct smbios_filter_param {
u32 offset;
u32 size;
bool is_string;
};
struct smbios_filter_table {
int type;
struct smbios_filter_param *params;
u32 count;
};
struct smbios_filter_param smbios_type1_filter_params[] = {
{offsetof(struct smbios_type1, serial_number),
FIELD_SIZEOF(struct smbios_type1, serial_number), true},
{offsetof(struct smbios_type1, uuid),
FIELD_SIZEOF(struct smbios_type1, uuid), false},
{offsetof(struct smbios_type1, wakeup_type),
FIELD_SIZEOF(struct smbios_type1, wakeup_type), false},
};
struct smbios_filter_param smbios_type2_filter_params[] = {
{offsetof(struct smbios_type2, serial_number),
FIELD_SIZEOF(struct smbios_type2, serial_number), true},
{offsetof(struct smbios_type2, chassis_location),
FIELD_SIZEOF(struct smbios_type2, chassis_location), false},
};
struct smbios_filter_param smbios_type3_filter_params[] = {
{offsetof(struct smbios_type3, serial_number),
FIELD_SIZEOF(struct smbios_type3, serial_number), true},
{offsetof(struct smbios_type3, asset_tag_number),
FIELD_SIZEOF(struct smbios_type3, asset_tag_number), true},
};
struct smbios_filter_param smbios_type4_filter_params[] = {
{offsetof(struct smbios_type4, serial_number),
FIELD_SIZEOF(struct smbios_type4, serial_number), true},
{offsetof(struct smbios_type4, asset_tag),
FIELD_SIZEOF(struct smbios_type4, asset_tag), true},
{offsetof(struct smbios_type4, part_number),
FIELD_SIZEOF(struct smbios_type4, part_number), true},
{offsetof(struct smbios_type4, core_count),
FIELD_SIZEOF(struct smbios_type4, core_count), false},
{offsetof(struct smbios_type4, core_enabled),
FIELD_SIZEOF(struct smbios_type4, core_enabled), false},
{offsetof(struct smbios_type4, thread_count),
FIELD_SIZEOF(struct smbios_type4, thread_count), false},
{offsetof(struct smbios_type4, core_count2),
FIELD_SIZEOF(struct smbios_type4, core_count2), false},
{offsetof(struct smbios_type4, core_enabled2),
FIELD_SIZEOF(struct smbios_type4, core_enabled2), false},
{offsetof(struct smbios_type4, thread_count2),
FIELD_SIZEOF(struct smbios_type4, thread_count2), false},
{offsetof(struct smbios_type4, voltage),
FIELD_SIZEOF(struct smbios_type4, voltage), false},
};
struct smbios_filter_table smbios_filter_tables[] = {
{SMBIOS_SYSTEM_INFORMATION, smbios_type1_filter_params,
ARRAY_SIZE(smbios_type1_filter_params)},
{SMBIOS_BOARD_INFORMATION, smbios_type2_filter_params,
ARRAY_SIZE(smbios_type2_filter_params)},
{SMBIOS_SYSTEM_ENCLOSURE, smbios_type3_filter_params,
ARRAY_SIZE(smbios_type3_filter_params)},
{SMBIOS_PROCESSOR_INFORMATION, smbios_type4_filter_params,
ARRAY_SIZE(smbios_type4_filter_params)},
};
static void clear_smbios_table(struct smbios_header *header,
struct smbios_filter_param *filter,
u32 count)
{
u32 i;
char *str;
u8 string_id;
for (i = 0; i < count; i++) {
if (filter[i].is_string) {
string_id = *((u8 *)header + filter[i].offset);
if (string_id == 0) /* string is empty */
continue;
str = smbios_string(header, string_id);
if (!str)
continue;
/* string is cleared to space, keep '\0' terminator */
memset(str, ' ', strlen(str));
} else {
memset((void *)((u8 *)header + filter[i].offset),
0, filter[i].size);
}
}
}
void smbios_prepare_measurement(const struct smbios_entry *entry,
struct smbios_header *smbios_copy)
{
u32 i, j;
struct smbios_header *header;
for (i = 0; i < ARRAY_SIZE(smbios_filter_tables); i++) {
header = smbios_copy;
for (j = 0; j < entry->struct_count; j++) {
if (header->type == smbios_filter_tables[i].type)
break;
header = get_next_header(header);
}
if (j >= entry->struct_count)
continue;
clear_smbios_table(header,
smbios_filter_tables[i].params,
smbios_filter_tables[i].count);
}
}

View File

@ -4,22 +4,17 @@
* Author: AKASHI Takahiro
*/
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "fdt_host.h"
typedef __u8 u8;
typedef __u16 u16;
typedef __u32 u32;
@ -29,9 +24,6 @@ typedef __s32 s32;
#define aligned_u64 __aligned_u64
#define SIGNATURE_NODENAME "signature"
#define OVERLAY_NODENAME "__overlay__"
#ifndef __packed
#define __packed __attribute__((packed))
#endif
@ -52,9 +44,6 @@ static struct option options[] = {
{"raw", required_argument, NULL, 'r'},
{"index", required_argument, NULL, 'i'},
{"instance", required_argument, NULL, 'I'},
{"dtb", required_argument, NULL, 'D'},
{"public key", required_argument, NULL, 'K'},
{"overlay", no_argument, NULL, 'O'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
@ -68,187 +57,10 @@ static void print_usage(void)
"\t-r, --raw <raw image> new raw image file\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
"\t-K, --public-key <key file> public key esl file\n"
"\t-D, --dtb <dtb file> dtb file\n"
"\t-O, --overlay the dtb file is an overlay\n"
"\t-h, --help print a help message\n",
tool_name);
}
static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,
bool overlay)
{
int parent;
int ov_node;
int frag_node;
int ret = 0;
if (overlay) {
/*
* The signature would be stored in the
* first fragment node of the overlay
*/
frag_node = fdt_first_subnode(dptr, 0);
if (frag_node == -FDT_ERR_NOTFOUND) {
fprintf(stderr,
"Couldn't find the fragment node: %s\n",
fdt_strerror(frag_node));
goto done;
}
ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);
if (ov_node == -FDT_ERR_NOTFOUND) {
fprintf(stderr,
"Couldn't find the __overlay__ node: %s\n",
fdt_strerror(ov_node));
goto done;
}
} else {
ov_node = 0;
}
parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);
if (parent == -FDT_ERR_NOTFOUND) {
parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);
if (parent < 0) {
ret = parent;
if (ret != -FDT_ERR_NOSPACE) {
fprintf(stderr,
"Couldn't create signature node: %s\n",
fdt_strerror(parent));
}
}
}
if (ret)
goto done;
/* Write the key to the FDT node */
ret = fdt_setprop(dptr, parent, "capsule-key",
sptr, key_size);
done:
if (ret)
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
return ret;
}
static int add_public_key(const char *pkey_file, const char *dtb_file,
bool overlay)
{
int ret;
int srcfd = -1;
int destfd = -1;
void *sptr = NULL;
void *dptr = NULL;
off_t src_size;
struct stat pub_key;
struct stat dtb;
/* Find out the size of the public key */
srcfd = open(pkey_file, O_RDONLY);
if (srcfd == -1) {
fprintf(stderr, "%s: Can't open %s: %s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
ret = fstat(srcfd, &pub_key);
if (ret == -1) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
src_size = pub_key.st_size;
/* mmap the public key esl file */
sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);
if (sptr == MAP_FAILED) {
fprintf(stderr, "%s: Failed to mmap %s:%s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
/* Open the dest FDT */
destfd = open(dtb_file, O_RDWR);
if (destfd == -1) {
fprintf(stderr, "%s: Can't open %s: %s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
ret = fstat(destfd, &dtb);
if (ret == -1) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
__func__, dtb_file, strerror(errno));
goto err;
}
dtb.st_size += src_size + 0x30;
if (ftruncate(destfd, dtb.st_size)) {
fprintf(stderr, "%s: Can't expand %s: %s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
errno = 0;
/* mmap the dtb file */
dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
destfd, 0);
if (dptr == MAP_FAILED) {
fprintf(stderr, "%s: Failed to mmap %s:%s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
if (fdt_check_header(dptr)) {
fprintf(stderr, "%s: Invalid FDT header\n", __func__);
ret = -1;
goto err;
}
ret = fdt_open_into(dptr, dptr, dtb.st_size);
if (ret) {
fprintf(stderr, "%s: Cannot expand FDT: %s\n",
__func__, fdt_strerror(ret));
ret = -1;
goto err;
}
/* Copy the esl file to the expanded FDT */
ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
if (ret < 0) {
fprintf(stderr, "%s: Unable to add public key to the FDT\n",
__func__);
ret = -1;
goto err;
}
ret = 0;
err:
if (sptr)
munmap(sptr, src_size);
if (dptr)
munmap(dptr, dtb.st_size);
if (srcfd != -1)
close(srcfd);
if (destfd != -1)
close(destfd);
return ret;
}
static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
{
@ -366,22 +178,16 @@ err_1:
int main(int argc, char **argv)
{
char *file;
char *pkey_file;
char *dtb_file;
efi_guid_t *guid;
unsigned long index, instance;
int c, idx;
int ret;
bool overlay = false;
file = NULL;
pkey_file = NULL;
dtb_file = NULL;
guid = NULL;
index = 0;
instance = 0;
for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
if (c == -1)
break;
@ -408,43 +214,22 @@ int main(int argc, char **argv)
case 'I':
instance = strtoul(optarg, NULL, 0);
break;
case 'K':
if (pkey_file) {
printf("Public Key already specified\n");
return -1;
}
pkey_file = optarg;
break;
case 'D':
if (dtb_file) {
printf("DTB file already specified\n");
return -1;
}
dtb_file = optarg;
break;
case 'O':
overlay = true;
break;
case 'h':
print_usage();
return 0;
}
}
/* need a fit image file or raw image file */
if (!file && !pkey_file && !dtb_file) {
/* need an output file */
if (argc != optind + 1) {
print_usage();
exit(EXIT_FAILURE);
}
if (pkey_file && dtb_file) {
ret = add_public_key(pkey_file, dtb_file, overlay);
if (ret == -1) {
printf("Adding public key to the dtb failed\n");
exit(EXIT_FAILURE);
} else {
exit(EXIT_SUCCESS);
}
/* need a fit image file or raw image file */
if (!file) {
print_usage();
exit(EXIT_SUCCESS);
}
if (create_fwbin(argv[optind], file, guid, index, instance)