uboot/lib/efi/efi_app.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 *
   5 * EFI information obtained here:
   6 * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
   7 *
   8 * This file implements U-Boot running as an EFI application.
   9 */
  10
  11#include <common.h>
  12#include <debug_uart.h>
  13#include <dm.h>
  14#include <errno.h>
  15#include <linux/err.h>
  16#include <linux/types.h>
  17#include <efi.h>
  18#include <efi_api.h>
  19#include <sysreset.h>
  20
  21DECLARE_GLOBAL_DATA_PTR;
  22
  23static struct efi_priv *global_priv;
  24
  25struct efi_system_table *efi_get_sys_table(void)
  26{
  27        return global_priv->sys_table;
  28}
  29
  30unsigned long efi_get_ram_base(void)
  31{
  32        return global_priv->ram_base;
  33}
  34
  35static efi_status_t setup_memory(struct efi_priv *priv)
  36{
  37        struct efi_boot_services *boot = priv->boot;
  38        efi_physical_addr_t addr;
  39        efi_status_t ret;
  40        int pages;
  41
  42        /*
  43         * Use global_data_ptr instead of gd since it is an assignment. There
  44         * are very few assignments to global_data in U-Boot and this makes
  45         * it easier to find them.
  46         */
  47        global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret);
  48        if (!global_data_ptr)
  49                return ret;
  50        memset(gd, '\0', sizeof(*gd));
  51
  52        gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_VAL(SYS_MALLOC_F_LEN),
  53                                            &ret);
  54        if (!gd->malloc_base)
  55                return ret;
  56        pages = CONFIG_EFI_RAM_SIZE >> 12;
  57
  58        /*
  59         * Don't allocate any memory above 4GB. U-Boot is a 32-bit application
  60         * so we want it to load below 4GB.
  61         */
  62        addr = 1ULL << 32;
  63        ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
  64                                   priv->image_data_type, pages, &addr);
  65        if (ret) {
  66                printf("(using pool %lx) ", ret);
  67                priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE,
  68                                                   &ret);
  69                if (!priv->ram_base)
  70                        return ret;
  71                priv->use_pool_for_malloc = true;
  72        } else {
  73                priv->ram_base = addr;
  74        }
  75        gd->ram_size = pages << 12;
  76
  77        return 0;
  78}
  79
  80static void free_memory(struct efi_priv *priv)
  81{
  82        struct efi_boot_services *boot = priv->boot;
  83
  84        if (priv->use_pool_for_malloc)
  85                efi_free(priv, (void *)priv->ram_base);
  86        else
  87                boot->free_pages(priv->ram_base, gd->ram_size >> 12);
  88
  89        efi_free(priv, (void *)gd->malloc_base);
  90        efi_free(priv, gd);
  91        global_data_ptr = NULL;
  92}
  93
  94/**
  95 * efi_main() - Start an EFI image
  96 *
  97 * This function is called by our EFI start-up code. It handles running
  98 * U-Boot. If it returns, EFI will continue. Another way to get back to EFI
  99 * is via reset_cpu().
 100 */
 101efi_status_t EFIAPI efi_main(efi_handle_t image,
 102                             struct efi_system_table *sys_table)
 103{
 104        struct efi_priv local_priv, *priv = &local_priv;
 105        efi_status_t ret;
 106
 107        /* Set up access to EFI data structures */
 108        efi_init(priv, "App", image, sys_table);
 109
 110        global_priv = priv;
 111
 112        /*
 113         * Set up the EFI debug UART so that printf() works. This is
 114         * implemented in the EFI serial driver, serial_efi.c. The application
 115         * can use printf() freely.
 116         */
 117        debug_uart_init();
 118
 119        ret = setup_memory(priv);
 120        if (ret) {
 121                printf("Failed to set up memory: ret=%lx\n", ret);
 122                return ret;
 123        }
 124
 125        printf("starting\n");
 126
 127        board_init_f(GD_FLG_SKIP_RELOC);
 128        board_init_r(NULL, 0);
 129        free_memory(priv);
 130
 131        return EFI_SUCCESS;
 132}
 133
 134static void efi_exit(void)
 135{
 136        struct efi_priv *priv = global_priv;
 137
 138        free_memory(priv);
 139        printf("U-Boot EFI exiting\n");
 140        priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL);
 141}
 142
 143static int efi_sysreset_request(struct udevice *dev, enum sysreset_t type)
 144{
 145        efi_exit();
 146
 147        return -EINPROGRESS;
 148}
 149
 150static const struct udevice_id efi_sysreset_ids[] = {
 151        { .compatible = "efi,reset" },
 152        { }
 153};
 154
 155static struct sysreset_ops efi_sysreset_ops = {
 156        .request = efi_sysreset_request,
 157};
 158
 159U_BOOT_DRIVER(efi_sysreset) = {
 160        .name = "efi-sysreset",
 161        .id = UCLASS_SYSRESET,
 162        .of_match = efi_sysreset_ids,
 163        .ops = &efi_sysreset_ops,
 164};
 165