uboot/arch/arm/cpu/armv8/sec_firmware.c
<<
>>
Prefs
   1/*
   2 * Copyright 2016 NXP Semiconductor, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <errno.h>
   9#include <linux/kernel.h>
  10#include <asm/io.h>
  11#include <asm/system.h>
  12#include <asm/types.h>
  13#include <asm/macro.h>
  14#include <asm/armv8/sec_firmware.h>
  15
  16DECLARE_GLOBAL_DATA_PTR;
  17extern void c_runtime_cpu_setup(void);
  18
  19#define SEC_FIRMWARE_LOADED     0x1
  20#define SEC_FIRMWARE_RUNNING    0x2
  21#define SEC_FIRMWARE_ADDR_MASK  (~0x3)
  22/*
  23 * Secure firmware load addr
  24 * Flags used: 0x1 secure firmware has been loaded to secure memory
  25 *             0x2 secure firmware is running
  26 */
  27phys_addr_t sec_firmware_addr;
  28
  29#ifndef SEC_FIRMWARE_FIT_IMAGE
  30#define SEC_FIRMWARE_FIT_IMAGE          "firmware"
  31#endif
  32#ifndef SEC_FIRMEWARE_FIT_CNF_NAME
  33#define SEC_FIRMEWARE_FIT_CNF_NAME      "config@1"
  34#endif
  35#ifndef SEC_FIRMWARE_TARGET_EL
  36#define SEC_FIRMWARE_TARGET_EL          2
  37#endif
  38
  39static int sec_firmware_get_data(const void *sec_firmware_img,
  40                                const void **data, size_t *size)
  41{
  42        int conf_node_off, fw_node_off;
  43        char *conf_node_name = NULL;
  44        char *desc;
  45        int ret;
  46
  47        conf_node_name = SEC_FIRMEWARE_FIT_CNF_NAME;
  48
  49        conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
  50        if (conf_node_off < 0) {
  51                printf("SEC Firmware: %s: no such config\n", conf_node_name);
  52                return -ENOENT;
  53        }
  54
  55        fw_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
  56                        SEC_FIRMWARE_FIT_IMAGE);
  57        if (fw_node_off < 0) {
  58                printf("SEC Firmware: No '%s' in config\n",
  59                       SEC_FIRMWARE_FIT_IMAGE);
  60                return -ENOLINK;
  61        }
  62
  63        /* Verify secure firmware image */
  64        if (!(fit_image_verify(sec_firmware_img, fw_node_off))) {
  65                printf("SEC Firmware: Bad firmware image (bad CRC)\n");
  66                return -EINVAL;
  67        }
  68
  69        if (fit_image_get_data(sec_firmware_img, fw_node_off, data, size)) {
  70                printf("SEC Firmware: Can't get %s subimage data/size",
  71                       SEC_FIRMWARE_FIT_IMAGE);
  72                return -ENOENT;
  73        }
  74
  75        ret = fit_get_desc(sec_firmware_img, fw_node_off, &desc);
  76        if (ret)
  77                printf("SEC Firmware: Can't get description\n");
  78        else
  79                printf("%s\n", desc);
  80
  81        return ret;
  82}
  83
  84/*
  85 * SEC Firmware FIT image parser checks if the image is in FIT
  86 * format, verifies integrity of the image and calculates raw
  87 * image address and size values.
  88 *
  89 * Returns 0 on success and a negative errno on error task fail.
  90 */
  91static int sec_firmware_parse_image(const void *sec_firmware_img,
  92                                        const void **raw_image_addr,
  93                                        size_t *raw_image_size)
  94{
  95        int ret;
  96
  97        ret = sec_firmware_get_data(sec_firmware_img, raw_image_addr,
  98                                        raw_image_size);
  99        if (ret)
 100                return ret;
 101
 102        debug("SEC Firmware: raw_image_addr = 0x%p, raw_image_size = 0x%lx\n",
 103              *raw_image_addr, *raw_image_size);
 104
 105        return 0;
 106}
 107
 108/*
 109 * SEC Firmware FIT image parser to check if any loadable is
 110 * present. If present, verify integrity of the loadable and
 111 * copy loadable to address provided in (loadable_h, loadable_l).
 112 *
 113 * Returns 0 on success and a negative errno on error task fail.
 114 */
 115static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
 116                                            u32 *loadable_l, u32 *loadable_h)
 117{
 118        phys_addr_t sec_firmware_loadable_addr = 0;
 119        int conf_node_off, ld_node_off;
 120        char *conf_node_name = NULL;
 121        const void *data;
 122        size_t size;
 123        ulong load;
 124
 125        conf_node_name = SEC_FIRMEWARE_FIT_CNF_NAME;
 126
 127        conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
 128        if (conf_node_off < 0) {
 129                printf("SEC Firmware: %s: no such config\n", conf_node_name);
 130        return -ENOENT;
 131        }
 132
 133        ld_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
 134                                             FIT_LOADABLE_PROP);
 135        if (ld_node_off >= 0) {
 136                printf("SEC Firmware: '%s' present in config\n",
 137                       FIT_LOADABLE_PROP);
 138
 139                /* Verify secure firmware image */
 140                if (!(fit_image_verify(sec_firmware_img, ld_node_off))) {
 141                        printf("SEC Loadable: Bad loadable image (bad CRC)\n");
 142                        return -EINVAL;
 143                }
 144
 145                if (fit_image_get_data(sec_firmware_img, ld_node_off,
 146                                       &data, &size)) {
 147                        printf("SEC Loadable: Can't get subimage data/size");
 148                        return -ENOENT;
 149                }
 150
 151                /* Get load address, treated as load offset to secure memory */
 152                if (fit_image_get_load(sec_firmware_img, ld_node_off, &load)) {
 153                        printf("SEC Loadable: Can't get subimage load");
 154                        return -ENOENT;
 155                }
 156
 157                /* Compute load address for loadable in secure memory */
 158                sec_firmware_loadable_addr = (sec_firmware_addr -
 159                                                gd->arch.tlb_size) + load;
 160
 161                /* Copy loadable to secure memory and flush dcache */
 162                debug("%s copied to address 0x%p\n",
 163                      FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr);
 164                memcpy((void *)sec_firmware_loadable_addr, data, size);
 165                flush_dcache_range(sec_firmware_loadable_addr,
 166                                   sec_firmware_loadable_addr + size);
 167        }
 168
 169        /* Populate address ptrs for loadable image with loadbale addr */
 170        out_le32(loadable_l, (sec_firmware_loadable_addr & WORD_MASK));
 171        out_le32(loadable_h, (sec_firmware_loadable_addr >> WORD_SHIFT));
 172
 173        return 0;
 174}
 175
 176static int sec_firmware_copy_image(const char *title,
 177                         u64 image_addr, u32 image_size, u64 sec_firmware)
 178{
 179        debug("%s copied to address 0x%p\n", title, (void *)sec_firmware);
 180        memcpy((void *)sec_firmware, (void *)image_addr, image_size);
 181        flush_dcache_range(sec_firmware, sec_firmware + image_size);
 182
 183        return 0;
 184}
 185
 186/*
 187 * This function will parse the SEC Firmware image, and then load it
 188 * to secure memory. Also load any loadable if present along with SEC
 189 * Firmware image.
 190 */
 191static int sec_firmware_load_image(const void *sec_firmware_img,
 192                                   u32 *loadable_l, u32 *loadable_h)
 193{
 194        const void *raw_image_addr;
 195        size_t raw_image_size = 0;
 196        int ret;
 197
 198        /*
 199         * The Excetpion Level must be EL3 to load and initialize
 200         * the SEC Firmware.
 201         */
 202        if (current_el() != 3) {
 203                ret = -EACCES;
 204                goto out;
 205        }
 206
 207#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
 208        /*
 209         * The SEC Firmware must be stored in secure memory.
 210         * Append SEC Firmware to secure mmu table.
 211         */
 212        if (!(gd->arch.secure_ram & MEM_RESERVE_SECURE_MAINTAINED)) {
 213                ret = -ENXIO;
 214                goto out;
 215        }
 216
 217        sec_firmware_addr = (gd->arch.secure_ram & MEM_RESERVE_SECURE_ADDR_MASK) +
 218                        gd->arch.tlb_size;
 219#else
 220#error "The CONFIG_SYS_MEM_RESERVE_SECURE must be defined when enabled SEC Firmware support"
 221#endif
 222
 223        /* Align SEC Firmware base address to 4K */
 224        sec_firmware_addr = (sec_firmware_addr + 0xfff) & ~0xfff;
 225        debug("SEC Firmware: Load address: 0x%llx\n",
 226              sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
 227
 228        ret = sec_firmware_parse_image(sec_firmware_img, &raw_image_addr,
 229                        &raw_image_size);
 230        if (ret)
 231                goto out;
 232
 233        /* TODO:
 234         * Check if the end addr of SEC Firmware has been extend the secure
 235         * memory.
 236         */
 237
 238        /* Copy the secure firmware to secure memory */
 239        ret = sec_firmware_copy_image("SEC Firmware", (u64)raw_image_addr,
 240                        raw_image_size, sec_firmware_addr &
 241                        SEC_FIRMWARE_ADDR_MASK);
 242        if (ret)
 243                goto out;
 244
 245        /*
 246         * Check if any loadable are present along with firmware image, if
 247         * present load them.
 248         */
 249        ret = sec_firmware_check_copy_loadable(sec_firmware_img, loadable_l,
 250                                               loadable_h);
 251        if (ret)
 252                goto out;
 253
 254        sec_firmware_addr |= SEC_FIRMWARE_LOADED;
 255        debug("SEC Firmware: Entry point: 0x%llx\n",
 256              sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
 257
 258        return 0;
 259
 260out:
 261        printf("SEC Firmware: error (%d)\n", ret);
 262        sec_firmware_addr = 0;
 263
 264        return ret;
 265}
 266
 267static int sec_firmware_entry(u32 *eret_hold_l, u32 *eret_hold_h)
 268{
 269        const void *entry = (void *)(sec_firmware_addr &
 270                                SEC_FIRMWARE_ADDR_MASK);
 271
 272        return _sec_firmware_entry(entry, eret_hold_l, eret_hold_h);
 273}
 274
 275/* Check the secure firmware FIT image */
 276__weak bool sec_firmware_is_valid(const void *sec_firmware_img)
 277{
 278        if (fdt_check_header(sec_firmware_img)) {
 279                printf("SEC Firmware: Bad firmware image (not a FIT image)\n");
 280                return false;
 281        }
 282
 283        if (!fit_check_format(sec_firmware_img)) {
 284                printf("SEC Firmware: Bad firmware image (bad FIT header)\n");
 285                return false;
 286        }
 287
 288        return true;
 289}
 290
 291#ifdef CONFIG_SEC_FIRMWARE_ARMV8_PSCI
 292/*
 293 * The PSCI_VERSION function is added from PSCI v0.2. When the PSCI
 294 * v0.1 received this function, the NOT_SUPPORTED (0xffff_ffff) error
 295 * number will be returned according to SMC Calling Conventions. But
 296 * when getting the NOT_SUPPORTED error number, we cannot ensure if
 297 * the PSCI version is v0.1 or other error occurred. So, PSCI v0.1
 298 * won't be supported by this framework.
 299 * And if the secure firmware isn't running, return NOT_SUPPORTED.
 300 *
 301 * The return value on success is PSCI version in format
 302 * major[31:16]:minor[15:0].
 303 */
 304unsigned int sec_firmware_support_psci_version(void)
 305{
 306        if (current_el() == SEC_FIRMWARE_TARGET_EL)
 307                return _sec_firmware_support_psci_version();
 308
 309        return PSCI_INVALID_VER;
 310}
 311#endif
 312
 313/*
 314 * Check with sec_firmware if it supports random number generation
 315 * via HW RNG
 316 *
 317 * The return value will be true if it is supported
 318 */
 319bool sec_firmware_support_hwrng(void)
 320{
 321        uint8_t rand[8];
 322        if (sec_firmware_addr & SEC_FIRMWARE_RUNNING) {
 323                if (!sec_firmware_get_random(rand, 8))
 324                        return true;
 325        }
 326
 327        return false;
 328}
 329
 330/*
 331 * sec_firmware_get_random - Get a random number from SEC Firmware
 332 * @rand:               random number buffer to be filled
 333 * @bytes:              Number of bytes of random number to be supported
 334 * @eret:               -1 in case of error, 0 for success
 335 */
 336int sec_firmware_get_random(uint8_t *rand, int bytes)
 337{
 338        unsigned long long num;
 339        struct pt_regs regs;
 340        int param1;
 341
 342        if (!bytes || bytes > 8) {
 343                printf("Max Random bytes genration supported is 8\n");
 344                return -1;
 345        }
 346#define SIP_RNG_64 0xC200FF11
 347        regs.regs[0] = SIP_RNG_64;
 348
 349        if (bytes <= 4)
 350                param1 = 0;
 351        else
 352                param1 = 1;
 353        regs.regs[1] = param1;
 354
 355        smc_call(&regs);
 356
 357        if (regs.regs[0])
 358                return -1;
 359
 360        num = regs.regs[1];
 361        memcpy(rand, &num, bytes);
 362
 363        return 0;
 364}
 365
 366/*
 367 * sec_firmware_init - Initialize the SEC Firmware
 368 * @sec_firmware_img:   the SEC Firmware image address
 369 * @eret_hold_l:        the address to hold exception return address low
 370 * @eret_hold_h:        the address to hold exception return address high
 371 * @loadable_l:         the address to hold loadable address low
 372 * @loadable_h:         the address to hold loadable address high
 373 */
 374int sec_firmware_init(const void *sec_firmware_img,
 375                        u32 *eret_hold_l,
 376                        u32 *eret_hold_h,
 377                        u32 *loadable_l,
 378                        u32 *loadable_h)
 379{
 380        int ret;
 381
 382        if (!sec_firmware_is_valid(sec_firmware_img))
 383                return -EINVAL;
 384
 385        ret = sec_firmware_load_image(sec_firmware_img, loadable_l,
 386                                      loadable_h);
 387        if (ret) {
 388                printf("SEC Firmware: Failed to load image\n");
 389                return ret;
 390        } else if (sec_firmware_addr & SEC_FIRMWARE_LOADED) {
 391                ret = sec_firmware_entry(eret_hold_l, eret_hold_h);
 392                if (ret) {
 393                        printf("SEC Firmware: Failed to initialize\n");
 394                        return ret;
 395                }
 396        }
 397
 398        debug("SEC Firmware: Return from SEC Firmware: current_el = %d\n",
 399              current_el());
 400
 401        /*
 402         * The PE will be turned into target EL when returned from
 403         * SEC Firmware.
 404         */
 405        if (current_el() != SEC_FIRMWARE_TARGET_EL)
 406                return -EACCES;
 407
 408        sec_firmware_addr |= SEC_FIRMWARE_RUNNING;
 409
 410        /* Set exception table and enable caches if it isn't EL3 */
 411        if (current_el() != 3) {
 412                c_runtime_cpu_setup();
 413                enable_caches();
 414        }
 415
 416        return 0;
 417}
 418
 419/*
 420 * fdt_fix_kaslr - Add kalsr-seed node in Device tree
 421 * @fdt:                Device tree
 422 * @eret:               0 in case of error, 1 for success
 423 */
 424int fdt_fixup_kaslr(void *fdt)
 425{
 426        int nodeoffset;
 427        int err, ret = 0;
 428        u8 rand[8];
 429
 430#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
 431        /* Check if random seed generation is  supported */
 432        if (sec_firmware_support_hwrng() == false)
 433                return 0;
 434
 435        ret = sec_firmware_get_random(rand, 8);
 436        if (ret < 0) {
 437                printf("WARNING: No random number to set kaslr-seed\n");
 438                return 0;
 439        }
 440
 441        err = fdt_check_header(fdt);
 442        if (err < 0) {
 443                printf("fdt_chosen: %s\n", fdt_strerror(err));
 444                return 0;
 445        }
 446
 447        /* find or create "/chosen" node. */
 448        nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
 449        if (nodeoffset < 0)
 450                return 0;
 451
 452        err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
 453                                  sizeof(rand));
 454        if (err < 0) {
 455                printf("WARNING: can't set kaslr-seed %s.\n",
 456                       fdt_strerror(err));
 457                return 0;
 458        }
 459        ret = 1;
 460#endif
 461
 462        return ret;
 463}
 464