Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2013 Linaro Ltd;  <roy.franz@linaro.org>
0004  */
0005 #include <linux/efi.h>
0006 #include <asm/efi.h>
0007 
0008 #include "efistub.h"
0009 
0010 static efi_guid_t cpu_state_guid = LINUX_EFI_ARM_CPU_STATE_TABLE_GUID;
0011 
0012 struct efi_arm_entry_state *efi_entry_state;
0013 
0014 static void get_cpu_state(u32 *cpsr, u32 *sctlr)
0015 {
0016     asm("mrs %0, cpsr" : "=r"(*cpsr));
0017     if ((*cpsr & MODE_MASK) == HYP_MODE)
0018         asm("mrc p15, 4, %0, c1, c0, 0" : "=r"(*sctlr));
0019     else
0020         asm("mrc p15, 0, %0, c1, c0, 0" : "=r"(*sctlr));
0021 }
0022 
0023 efi_status_t check_platform_features(void)
0024 {
0025     efi_status_t status;
0026     u32 cpsr, sctlr;
0027     int block;
0028 
0029     get_cpu_state(&cpsr, &sctlr);
0030 
0031     efi_info("Entering in %s mode with MMU %sabled\n",
0032          ((cpsr & MODE_MASK) == HYP_MODE) ? "HYP" : "SVC",
0033          (sctlr & 1) ? "en" : "dis");
0034 
0035     status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
0036                  sizeof(*efi_entry_state),
0037                  (void **)&efi_entry_state);
0038     if (status != EFI_SUCCESS) {
0039         efi_err("allocate_pool() failed\n");
0040         return status;
0041     }
0042 
0043     efi_entry_state->cpsr_before_ebs = cpsr;
0044     efi_entry_state->sctlr_before_ebs = sctlr;
0045 
0046     status = efi_bs_call(install_configuration_table, &cpu_state_guid,
0047                  efi_entry_state);
0048     if (status != EFI_SUCCESS) {
0049         efi_err("install_configuration_table() failed\n");
0050         goto free_state;
0051     }
0052 
0053     /* non-LPAE kernels can run anywhere */
0054     if (!IS_ENABLED(CONFIG_ARM_LPAE))
0055         return EFI_SUCCESS;
0056 
0057     /* LPAE kernels need compatible hardware */
0058     block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
0059     if (block < 5) {
0060         efi_err("This LPAE kernel is not supported by your CPU\n");
0061         status = EFI_UNSUPPORTED;
0062         goto drop_table;
0063     }
0064     return EFI_SUCCESS;
0065 
0066 drop_table:
0067     efi_bs_call(install_configuration_table, &cpu_state_guid, NULL);
0068 free_state:
0069     efi_bs_call(free_pool, efi_entry_state);
0070     return status;
0071 }
0072 
0073 void efi_handle_post_ebs_state(void)
0074 {
0075     get_cpu_state(&efi_entry_state->cpsr_after_ebs,
0076               &efi_entry_state->sctlr_after_ebs);
0077 }
0078 
0079 static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID;
0080 
0081 struct screen_info *alloc_screen_info(void)
0082 {
0083     struct screen_info *si;
0084     efi_status_t status;
0085 
0086     /*
0087      * Unlike on arm64, where we can directly fill out the screen_info
0088      * structure from the stub, we need to allocate a buffer to hold
0089      * its contents while we hand over to the kernel proper from the
0090      * decompressor.
0091      */
0092     status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
0093                  sizeof(*si), (void **)&si);
0094 
0095     if (status != EFI_SUCCESS)
0096         return NULL;
0097 
0098     status = efi_bs_call(install_configuration_table,
0099                  &screen_info_guid, si);
0100     if (status == EFI_SUCCESS)
0101         return si;
0102 
0103     efi_bs_call(free_pool, si);
0104     return NULL;
0105 }
0106 
0107 void free_screen_info(struct screen_info *si)
0108 {
0109     if (!si)
0110         return;
0111 
0112     efi_bs_call(install_configuration_table, &screen_info_guid, NULL);
0113     efi_bs_call(free_pool, si);
0114 }
0115 
0116 efi_status_t handle_kernel_image(unsigned long *image_addr,
0117                  unsigned long *image_size,
0118                  unsigned long *reserve_addr,
0119                  unsigned long *reserve_size,
0120                  efi_loaded_image_t *image,
0121                  efi_handle_t image_handle)
0122 {
0123     const int slack = TEXT_OFFSET - 5 * PAGE_SIZE;
0124     int alloc_size = MAX_UNCOMP_KERNEL_SIZE + EFI_PHYS_ALIGN;
0125     unsigned long alloc_base, kernel_base;
0126     efi_status_t status;
0127 
0128     /*
0129      * Allocate space for the decompressed kernel as low as possible.
0130      * The region should be 16 MiB aligned, but the first 'slack' bytes
0131      * are not used by Linux, so we allow those to be occupied by the
0132      * firmware.
0133      */
0134     status = efi_low_alloc_above(alloc_size, EFI_PAGE_SIZE, &alloc_base, 0x0);
0135     if (status != EFI_SUCCESS) {
0136         efi_err("Unable to allocate memory for uncompressed kernel.\n");
0137         return status;
0138     }
0139 
0140     if ((alloc_base % EFI_PHYS_ALIGN) > slack) {
0141         /*
0142          * More than 'slack' bytes are already occupied at the base of
0143          * the allocation, so we need to advance to the next 16 MiB block.
0144          */
0145         kernel_base = round_up(alloc_base, EFI_PHYS_ALIGN);
0146         efi_info("Free memory starts at 0x%lx, setting kernel_base to 0x%lx\n",
0147              alloc_base, kernel_base);
0148     } else {
0149         kernel_base = round_down(alloc_base, EFI_PHYS_ALIGN);
0150     }
0151 
0152     *reserve_addr = kernel_base + slack;
0153     *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
0154 
0155     /* now free the parts that we will not use */
0156     if (*reserve_addr > alloc_base) {
0157         efi_bs_call(free_pages, alloc_base,
0158                 (*reserve_addr - alloc_base) / EFI_PAGE_SIZE);
0159         alloc_size -= *reserve_addr - alloc_base;
0160     }
0161     efi_bs_call(free_pages, *reserve_addr + MAX_UNCOMP_KERNEL_SIZE,
0162             (alloc_size - MAX_UNCOMP_KERNEL_SIZE) / EFI_PAGE_SIZE);
0163 
0164     *image_addr = kernel_base + TEXT_OFFSET;
0165     *image_size = 0;
0166 
0167     efi_debug("image addr == 0x%lx, reserve_addr == 0x%lx\n",
0168           *image_addr, *reserve_addr);
0169 
0170     return EFI_SUCCESS;
0171 }