1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * EFI initialization |
4 | * |
5 | * Author: Jianmin Lv <lvjianmin@loongson.cn> |
6 | * Huacai Chen <chenhuacai@loongson.cn> |
7 | * |
8 | * Copyright (C) 2020-2022 Loongson Technology Corporation Limited |
9 | */ |
10 | |
11 | #include <linux/acpi.h> |
12 | #include <linux/efi.h> |
13 | #include <linux/efi-bgrt.h> |
14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/export.h> |
17 | #include <linux/io.h> |
18 | #include <linux/kobject.h> |
19 | #include <linux/memblock.h> |
20 | #include <linux/reboot.h> |
21 | #include <linux/screen_info.h> |
22 | #include <linux/uaccess.h> |
23 | |
24 | #include <asm/early_ioremap.h> |
25 | #include <asm/efi.h> |
26 | #include <asm/loongson.h> |
27 | |
28 | static unsigned long efi_nr_tables; |
29 | static unsigned long efi_config_table; |
30 | |
31 | static unsigned long __initdata boot_memmap = EFI_INVALID_TABLE_ADDR; |
32 | static unsigned long __initdata fdt_pointer = EFI_INVALID_TABLE_ADDR; |
33 | |
34 | static efi_system_table_t *efi_systab; |
35 | static efi_config_table_type_t arch_tables[] __initdata = { |
36 | {LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" }, |
37 | {DEVICE_TREE_GUID, &fdt_pointer, "FDTPTR" }, |
38 | {}, |
39 | }; |
40 | |
41 | void __init *efi_fdt_pointer(void) |
42 | { |
43 | if (!efi_systab) |
44 | return NULL; |
45 | |
46 | if (fdt_pointer == EFI_INVALID_TABLE_ADDR) |
47 | return NULL; |
48 | |
49 | return early_memremap_ro(phys_addr: fdt_pointer, SZ_64K); |
50 | } |
51 | |
52 | void __init efi_runtime_init(void) |
53 | { |
54 | if (!efi_enabled(EFI_BOOT) || !efi_systab->runtime) |
55 | return; |
56 | |
57 | if (efi_runtime_disabled()) { |
58 | pr_info("EFI runtime services will be disabled.\n" ); |
59 | return; |
60 | } |
61 | |
62 | efi.runtime = (efi_runtime_services_t *)efi_systab->runtime; |
63 | efi.runtime_version = (unsigned int)efi.runtime->hdr.revision; |
64 | |
65 | efi_native_runtime_setup(); |
66 | set_bit(EFI_RUNTIME_SERVICES, addr: &efi.flags); |
67 | } |
68 | |
69 | unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; |
70 | |
71 | #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON) |
72 | struct screen_info screen_info __section(".data" ); |
73 | EXPORT_SYMBOL_GPL(screen_info); |
74 | #endif |
75 | |
76 | static void __init init_screen_info(void) |
77 | { |
78 | struct screen_info *si; |
79 | |
80 | if (screen_info_table == EFI_INVALID_TABLE_ADDR) |
81 | return; |
82 | |
83 | si = early_memremap(phys_addr: screen_info_table, size: sizeof(*si)); |
84 | if (!si) { |
85 | pr_err("Could not map screen_info config table\n" ); |
86 | return; |
87 | } |
88 | screen_info = *si; |
89 | memset(si, 0, sizeof(*si)); |
90 | early_memunmap(addr: si, size: sizeof(*si)); |
91 | |
92 | memblock_reserve(base: screen_info.lfb_base, size: screen_info.lfb_size); |
93 | } |
94 | |
95 | void __init efi_init(void) |
96 | { |
97 | int size; |
98 | void *config_tables; |
99 | struct efi_boot_memmap *tbl; |
100 | |
101 | if (!efi_system_table) |
102 | return; |
103 | |
104 | efi_systab = (efi_system_table_t *)early_memremap_ro(phys_addr: efi_system_table, size: sizeof(*efi_systab)); |
105 | if (!efi_systab) { |
106 | pr_err("Can't find EFI system table.\n" ); |
107 | return; |
108 | } |
109 | |
110 | efi_systab_report_header(systab_hdr: &efi_systab->hdr, fw_vendor: efi_systab->fw_vendor); |
111 | |
112 | set_bit(EFI_64BIT, addr: &efi.flags); |
113 | efi_nr_tables = efi_systab->nr_tables; |
114 | efi_config_table = (unsigned long)efi_systab->tables; |
115 | |
116 | size = sizeof(efi_config_table_t); |
117 | config_tables = early_memremap(phys_addr: efi_config_table, size: efi_nr_tables * size); |
118 | efi_config_parse_tables(config_tables, count: efi_systab->nr_tables, arch_tables); |
119 | early_memunmap(addr: config_tables, size: efi_nr_tables * size); |
120 | |
121 | set_bit(EFI_CONFIG_TABLES, addr: &efi.flags); |
122 | |
123 | if (IS_ENABLED(CONFIG_EFI_EARLYCON) || IS_ENABLED(CONFIG_SYSFB)) |
124 | init_screen_info(); |
125 | |
126 | if (boot_memmap == EFI_INVALID_TABLE_ADDR) |
127 | return; |
128 | |
129 | tbl = early_memremap_ro(phys_addr: boot_memmap, size: sizeof(*tbl)); |
130 | if (tbl) { |
131 | struct efi_memory_map_data data; |
132 | |
133 | data.phys_map = boot_memmap + sizeof(*tbl); |
134 | data.size = tbl->map_size; |
135 | data.desc_size = tbl->desc_size; |
136 | data.desc_version = tbl->desc_ver; |
137 | |
138 | if (efi_memmap_init_early(data: &data) < 0) |
139 | panic(fmt: "Unable to map EFI memory map.\n" ); |
140 | |
141 | early_memunmap(addr: tbl, size: sizeof(*tbl)); |
142 | } |
143 | |
144 | efi_esrt_init(); |
145 | } |
146 | |