uboot/tools/mkeficapsule.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2018 Linaro Limited
   4 *              Author: AKASHI Takahiro
   5 */
   6
   7#include <getopt.h>
   8#include <malloc.h>
   9#include <stdbool.h>
  10#include <stdio.h>
  11#include <stdlib.h>
  12#include <string.h>
  13#include <linux/types.h>
  14
  15#include <sys/stat.h>
  16#include <sys/types.h>
  17
  18typedef __u8 u8;
  19typedef __u16 u16;
  20typedef __u32 u32;
  21typedef __u64 u64;
  22typedef __s16 s16;
  23typedef __s32 s32;
  24
  25#define aligned_u64 __aligned_u64
  26
  27#ifndef __packed
  28#define __packed __attribute__((packed))
  29#endif
  30
  31#include <efi.h>
  32#include <efi_api.h>
  33
  34static const char *tool_name = "mkeficapsule";
  35
  36efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
  37efi_guid_t efi_guid_image_type_uboot_fit =
  38                EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
  39efi_guid_t efi_guid_image_type_uboot_raw =
  40                EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
  41
  42static struct option options[] = {
  43        {"fit", required_argument, NULL, 'f'},
  44        {"raw", required_argument, NULL, 'r'},
  45        {"index", required_argument, NULL, 'i'},
  46        {"instance", required_argument, NULL, 'I'},
  47        {"help", no_argument, NULL, 'h'},
  48        {NULL, 0, NULL, 0},
  49};
  50
  51static void print_usage(void)
  52{
  53        printf("Usage: %s [options] <output file>\n"
  54               "Options:\n"
  55
  56               "\t-f, --fit <fit image>       new FIT image file\n"
  57               "\t-r, --raw <raw image>       new raw image file\n"
  58               "\t-i, --index <index>         update image index\n"
  59               "\t-I, --instance <instance>   update hardware instance\n"
  60               "\t-h, --help                  print a help message\n",
  61               tool_name);
  62}
  63
  64static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
  65                        unsigned long index, unsigned long instance)
  66{
  67        struct efi_capsule_header header;
  68        struct efi_firmware_management_capsule_header capsule;
  69        struct efi_firmware_management_capsule_image_header image;
  70        FILE *f, *g;
  71        struct stat bin_stat;
  72        u8 *data;
  73        size_t size;
  74        u64 offset;
  75
  76#ifdef DEBUG
  77        printf("For output: %s\n", path);
  78        printf("\tbin: %s\n\ttype: %pUl\n", bin, guid);
  79        printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
  80#endif
  81
  82        g = fopen(bin, "r");
  83        if (!g) {
  84                printf("cannot open %s\n", bin);
  85                return -1;
  86        }
  87        if (stat(bin, &bin_stat) < 0) {
  88                printf("cannot determine the size of %s\n", bin);
  89                goto err_1;
  90        }
  91        data = malloc(bin_stat.st_size);
  92        if (!data) {
  93                printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size);
  94                goto err_1;
  95        }
  96        f = fopen(path, "w");
  97        if (!f) {
  98                printf("cannot open %s\n", path);
  99                goto err_2;
 100        }
 101        header.capsule_guid = efi_guid_fm_capsule;
 102        header.header_size = sizeof(header);
 103        /* TODO: The current implementation ignores flags */
 104        header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
 105        header.capsule_image_size = sizeof(header)
 106                                        + sizeof(capsule) + sizeof(u64)
 107                                        + sizeof(image)
 108                                        + bin_stat.st_size;
 109
 110        size = fwrite(&header, 1, sizeof(header), f);
 111        if (size < sizeof(header)) {
 112                printf("write failed (%zx)\n", size);
 113                goto err_3;
 114        }
 115
 116        capsule.version = 0x00000001;
 117        capsule.embedded_driver_count = 0;
 118        capsule.payload_item_count = 1;
 119        size = fwrite(&capsule, 1, sizeof(capsule), f);
 120        if (size < (sizeof(capsule))) {
 121                printf("write failed (%zx)\n", size);
 122                goto err_3;
 123        }
 124        offset = sizeof(capsule) + sizeof(u64);
 125        size = fwrite(&offset, 1, sizeof(offset), f);
 126        if (size < sizeof(offset)) {
 127                printf("write failed (%zx)\n", size);
 128                goto err_3;
 129        }
 130
 131        image.version = 0x00000003;
 132        memcpy(&image.update_image_type_id, guid, sizeof(*guid));
 133        image.update_image_index = index;
 134        image.reserved[0] = 0;
 135        image.reserved[1] = 0;
 136        image.reserved[2] = 0;
 137        image.update_image_size = bin_stat.st_size;
 138        image.update_vendor_code_size = 0; /* none */
 139        image.update_hardware_instance = instance;
 140        image.image_capsule_support = 0;
 141
 142        size = fwrite(&image, 1, sizeof(image), f);
 143        if (size < sizeof(image)) {
 144                printf("write failed (%zx)\n", size);
 145                goto err_3;
 146        }
 147        size = fread(data, 1, bin_stat.st_size, g);
 148        if (size < bin_stat.st_size) {
 149                printf("read failed (%zx)\n", size);
 150                goto err_3;
 151        }
 152        size = fwrite(data, 1, bin_stat.st_size, f);
 153        if (size < bin_stat.st_size) {
 154                printf("write failed (%zx)\n", size);
 155                goto err_3;
 156        }
 157
 158        fclose(f);
 159        fclose(g);
 160        free(data);
 161
 162        return 0;
 163
 164err_3:
 165        fclose(f);
 166err_2:
 167        free(data);
 168err_1:
 169        fclose(g);
 170
 171        return -1;
 172}
 173
 174/*
 175 * Usage:
 176 *   $ mkeficapsule -f <firmware binary> <output file>
 177 */
 178int main(int argc, char **argv)
 179{
 180        char *file;
 181        efi_guid_t *guid;
 182        unsigned long index, instance;
 183        int c, idx;
 184
 185        file = NULL;
 186        guid = NULL;
 187        index = 0;
 188        instance = 0;
 189        for (;;) {
 190                c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
 191                if (c == -1)
 192                        break;
 193
 194                switch (c) {
 195                case 'f':
 196                        if (file) {
 197                                printf("Image already specified\n");
 198                                return -1;
 199                        }
 200                        file = optarg;
 201                        guid = &efi_guid_image_type_uboot_fit;
 202                        break;
 203                case 'r':
 204                        if (file) {
 205                                printf("Image already specified\n");
 206                                return -1;
 207                        }
 208                        file = optarg;
 209                        guid = &efi_guid_image_type_uboot_raw;
 210                        break;
 211                case 'i':
 212                        index = strtoul(optarg, NULL, 0);
 213                        break;
 214                case 'I':
 215                        instance = strtoul(optarg, NULL, 0);
 216                        break;
 217                case 'h':
 218                        print_usage();
 219                        return 0;
 220                }
 221        }
 222
 223        /* need an output file */
 224        if (argc != optind + 1) {
 225                print_usage();
 226                exit(EXIT_FAILURE);
 227        }
 228
 229        /* need a fit image file or raw image file */
 230        if (!file) {
 231                print_usage();
 232                exit(EXIT_SUCCESS);
 233        }
 234
 235        if (create_fwbin(argv[optind], file, guid, index, instance)
 236                        < 0) {
 237                printf("Creating firmware capsule failed\n");
 238                exit(EXIT_FAILURE);
 239        }
 240
 241        exit(EXIT_SUCCESS);
 242}
 243