1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Author: Yun Liu <liuyun@loongson.cn> 4 * Huacai Chen <chenhuacai@loongson.cn> 5 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 6 */ 7 8#include <asm/efi.h> 9#include <asm/addrspace.h> 10#include "efistub.h" 11 12#define BOOT_HEAP_SIZE 0x400000 13 14typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline, 15 unsigned long systab, long kdump_reloc_offset); 16 17extern long kernel_entaddr; 18extern void decompress_kernel(unsigned long boot_heap_start, long kdump_reloc_offset); 19 20static unsigned char efi_heap[BOOT_HEAP_SIZE]; 21static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID; 22static kernel_entry_t kernel_entry; 23 24struct screen_info *alloc_screen_info(void) 25{ 26 efi_status_t status; 27 struct screen_info *si; 28 29 status = efi_bs_call(allocate_pool, 30 EFI_RUNTIME_SERVICES_DATA, sizeof(*si), (void **)&si); 31 if (status != EFI_SUCCESS) 32 return NULL; 33 34 memset(si, 0, sizeof(*si)); 35 36 status = efi_bs_call(install_configuration_table, &screen_info_guid, si); 37 if (status == EFI_SUCCESS) 38 return si; 39 40 efi_bs_call(free_pool, si); 41 42 return NULL; 43} 44 45void free_screen_info(struct screen_info *si) 46{ 47 if (!si) 48 return; 49 50 efi_bs_call(install_configuration_table, &screen_info_guid, NULL); 51 efi_bs_call(free_pool, si); 52} 53 54efi_status_t check_platform_features(void) 55{ 56 return EFI_SUCCESS; 57} 58 59efi_status_t handle_kernel_image(unsigned long *image_addr, 60 unsigned long *image_size, 61 unsigned long *reserve_addr, 62 unsigned long *reserve_size, 63 efi_loaded_image_t *image) 64{ 65 /* Config Direct Mapping */ 66 csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); 67 csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); 68 69 decompress_kernel((unsigned long)efi_heap, 0); 70 kernel_entry = (kernel_entry_t)kernel_entaddr; 71 72 return EFI_SUCCESS; 73} 74 75struct exit_boot_struct { 76 efi_memory_desc_t *runtime_map; 77 int runtime_entry_count; 78}; 79 80static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv) 81{ 82 struct exit_boot_struct *p = priv; 83 84 /* 85 * Update the memory map with virtual addresses. The function will also 86 * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME 87 * entries so that we can pass it straight to SetVirtualAddressMap() 88 */ 89 efi_get_virtmap(map->map, map->map_size, map->desc_size, 90 p->runtime_map, &p->runtime_entry_count); 91 92 return EFI_SUCCESS; 93} 94 95efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, 96 unsigned long kernel_addr, char *cmdline_ptr) 97{ 98 struct exit_boot_struct priv; 99 unsigned long desc_size; 100 efi_status_t status; 101 u32 desc_ver; 102 103 status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver); 104 if (status != EFI_SUCCESS) { 105 efi_err("Unable to retrieve UEFI memory map.\n"); 106 return status; 107 } 108 109 efi_info("Exiting boot services\n"); 110 111 efi_novamap = false; 112 status = efi_exit_boot_services(handle, &priv, exit_boot_func); 113 if (status != EFI_SUCCESS) 114 return status; 115 116 /* Install the new virtual address map */ 117 efi_rt_call(set_virtual_address_map, 118 priv.runtime_entry_count * desc_size, desc_size, 119 desc_ver, priv.runtime_map); 120 121 kernel_entry(true, (unsigned long)cmdline_ptr, (unsigned long)efi_system_table, 0); 122} 123