1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
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 | |
14 | typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long); |
15 | |
16 | static unsigned long hartid; |
17 | |
18 | static 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, path: "/chosen" ); |
29 | if (chosen_node < 0) |
30 | return -EINVAL; |
31 | |
32 | prop = fdt_getprop(fdt: (void *)fdt, nodeoffset: chosen_node, name: "boot-hartid" , lenp: &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 | else |
41 | return -EINVAL; |
42 | |
43 | return 0; |
44 | } |
45 | |
46 | static 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 | |
59 | efi_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 | |
75 | unsigned long __weak stext_offset(void) |
76 | { |
77 | /* |
78 | * This fallback definition is used by the EFI zboot stub, which loads |
79 | * the entire image so it can branch via the image header at offset #0. |
80 | */ |
81 | return 0; |
82 | } |
83 | |
84 | void __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 hartid |
94 | * 3. a1 should DT address |
95 | */ |
96 | csr_write(CSR_SATP, 0); |
97 | jump_kernel(hartid, fdt); |
98 | } |
99 | |