99 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2020 Western Digital Corporation or its affiliates.4 */5 6#include <linux/efi.h>7#include <linux/libfdt.h>8 9#include <asm/efi.h>10#include <linux/unaligned.h>11 12#include "efistub.h"13 14typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long);15 16static unsigned long hartid;17 18static int get_boot_hartid_from_fdt(void)19{20 const void *fdt;21 int chosen_node, len;22 const void *prop;23 24 fdt = get_efi_config_table(DEVICE_TREE_GUID);25 if (!fdt)26 return -EINVAL;27 28 chosen_node = fdt_path_offset(fdt, "/chosen");29 if (chosen_node < 0)30 return -EINVAL;31 32 prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len);33 if (!prop)34 return -EINVAL;35 36 if (len == sizeof(u32))37 hartid = (unsigned long) fdt32_to_cpu(*(fdt32_t *)prop);38 else if (len == sizeof(u64))39 hartid = (unsigned long) fdt64_to_cpu(__get_unaligned_t(fdt64_t, prop));40 else41 return -EINVAL;42 43 return 0;44}45 46static efi_status_t get_boot_hartid_from_efi(void)47{48 efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;49 struct riscv_efi_boot_protocol *boot_protocol;50 efi_status_t status;51 52 status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,53 (void **)&boot_protocol);54 if (status != EFI_SUCCESS)55 return status;56 return efi_call_proto(boot_protocol, get_boot_hartid, &hartid);57}58 59efi_status_t check_platform_features(void)60{61 efi_status_t status;62 int ret;63 64 status = get_boot_hartid_from_efi();65 if (status != EFI_SUCCESS) {66 ret = get_boot_hartid_from_fdt();67 if (ret) {68 efi_err("Failed to get boot hartid!\n");69 return EFI_UNSUPPORTED;70 }71 }72 return EFI_SUCCESS;73}74 75unsigned long __weak stext_offset(void)76{77 /*78 * This fallback definition is used by the EFI zboot stub, which loads79 * the entire image so it can branch via the image header at offset #0.80 */81 return 0;82}83 84void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt,85 unsigned long fdt_size)86{87 unsigned long kernel_entry = entrypoint + stext_offset();88 jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry;89 90 /*91 * Jump to real kernel here with following constraints.92 * 1. MMU should be disabled.93 * 2. a0 should contain hartid94 * 3. a1 should DT address95 */96 csr_write(CSR_SATP, 0);97 jump_kernel(hartid, fdt);98}99