1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2009 Sunplus Core Technology Co., Ltd. |
4 | * Chen Liqin <liqin.chen@sunplusct.com> |
5 | * Lennox Wu <lennox.wu@sunplusct.com> |
6 | * Copyright (C) 2012 Regents of the University of California |
7 | * Copyright (C) 2020 FORTH-ICS/CARV |
8 | * Nick Kossifidis <mick@ics.forth.gr> |
9 | */ |
10 | |
11 | #include <linux/acpi.h> |
12 | #include <linux/cpu.h> |
13 | #include <linux/init.h> |
14 | #include <linux/mm.h> |
15 | #include <linux/memblock.h> |
16 | #include <linux/sched.h> |
17 | #include <linux/console.h> |
18 | #include <linux/of_fdt.h> |
19 | #include <linux/sched/task.h> |
20 | #include <linux/smp.h> |
21 | #include <linux/efi.h> |
22 | #include <linux/crash_dump.h> |
23 | #include <linux/panic_notifier.h> |
24 | |
25 | #include <asm/acpi.h> |
26 | #include <asm/alternative.h> |
27 | #include <asm/cacheflush.h> |
28 | #include <asm/cpufeature.h> |
29 | #include <asm/early_ioremap.h> |
30 | #include <asm/pgtable.h> |
31 | #include <asm/setup.h> |
32 | #include <asm/set_memory.h> |
33 | #include <asm/sections.h> |
34 | #include <asm/sbi.h> |
35 | #include <asm/tlbflush.h> |
36 | #include <asm/thread_info.h> |
37 | #include <asm/kasan.h> |
38 | #include <asm/efi.h> |
39 | |
40 | #include "head.h" |
41 | |
42 | /* |
43 | * The lucky hart to first increment this variable will boot the other cores. |
44 | * This is used before the kernel initializes the BSS so it can't be in the |
45 | * BSS. |
46 | */ |
47 | atomic_t hart_lottery __section(".sdata" ) |
48 | #ifdef CONFIG_XIP_KERNEL |
49 | = ATOMIC_INIT(0xC001BEEF) |
50 | #endif |
51 | ; |
52 | unsigned long boot_cpu_hartid; |
53 | |
54 | /* |
55 | * Place kernel memory regions on the resource tree so that |
56 | * kexec-tools can retrieve them from /proc/iomem. While there |
57 | * also add "System RAM" regions for compatibility with other |
58 | * archs, and the rest of the known regions for completeness. |
59 | */ |
60 | static struct resource kimage_res = { .name = "Kernel image" , }; |
61 | static struct resource code_res = { .name = "Kernel code" , }; |
62 | static struct resource data_res = { .name = "Kernel data" , }; |
63 | static struct resource rodata_res = { .name = "Kernel rodata" , }; |
64 | static struct resource bss_res = { .name = "Kernel bss" , }; |
65 | #ifdef CONFIG_CRASH_DUMP |
66 | static struct resource elfcorehdr_res = { .name = "ELF Core hdr" , }; |
67 | #endif |
68 | |
69 | static int __init add_resource(struct resource *parent, |
70 | struct resource *res) |
71 | { |
72 | int ret = 0; |
73 | |
74 | ret = insert_resource(parent, new: res); |
75 | if (ret < 0) { |
76 | pr_err("Failed to add a %s resource at %llx\n" , |
77 | res->name, (unsigned long long) res->start); |
78 | return ret; |
79 | } |
80 | |
81 | return 1; |
82 | } |
83 | |
84 | static int __init add_kernel_resources(void) |
85 | { |
86 | int ret = 0; |
87 | |
88 | /* |
89 | * The memory region of the kernel image is continuous and |
90 | * was reserved on setup_bootmem, register it here as a |
91 | * resource, with the various segments of the image as |
92 | * child nodes. |
93 | */ |
94 | |
95 | code_res.start = __pa_symbol(_text); |
96 | code_res.end = __pa_symbol(_etext) - 1; |
97 | code_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
98 | |
99 | rodata_res.start = __pa_symbol(__start_rodata); |
100 | rodata_res.end = __pa_symbol(__end_rodata) - 1; |
101 | rodata_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
102 | |
103 | data_res.start = __pa_symbol(_data); |
104 | data_res.end = __pa_symbol(_edata) - 1; |
105 | data_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
106 | |
107 | bss_res.start = __pa_symbol(__bss_start); |
108 | bss_res.end = __pa_symbol(__bss_stop) - 1; |
109 | bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
110 | |
111 | kimage_res.start = code_res.start; |
112 | kimage_res.end = bss_res.end; |
113 | kimage_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
114 | |
115 | ret = add_resource(parent: &iomem_resource, res: &kimage_res); |
116 | if (ret < 0) |
117 | return ret; |
118 | |
119 | ret = add_resource(parent: &kimage_res, res: &code_res); |
120 | if (ret < 0) |
121 | return ret; |
122 | |
123 | ret = add_resource(parent: &kimage_res, res: &rodata_res); |
124 | if (ret < 0) |
125 | return ret; |
126 | |
127 | ret = add_resource(parent: &kimage_res, res: &data_res); |
128 | if (ret < 0) |
129 | return ret; |
130 | |
131 | ret = add_resource(parent: &kimage_res, res: &bss_res); |
132 | |
133 | return ret; |
134 | } |
135 | |
136 | static void __init init_resources(void) |
137 | { |
138 | struct memblock_region *region = NULL; |
139 | struct resource *res = NULL; |
140 | struct resource *mem_res = NULL; |
141 | size_t mem_res_sz = 0; |
142 | int num_resources = 0, res_idx = 0; |
143 | int ret = 0; |
144 | |
145 | /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ |
146 | num_resources = memblock.memory.cnt + memblock.reserved.cnt + 1; |
147 | res_idx = num_resources - 1; |
148 | |
149 | mem_res_sz = num_resources * sizeof(*mem_res); |
150 | mem_res = memblock_alloc(size: mem_res_sz, SMP_CACHE_BYTES); |
151 | if (!mem_res) |
152 | panic(fmt: "%s: Failed to allocate %zu bytes\n" , __func__, mem_res_sz); |
153 | |
154 | /* |
155 | * Start by adding the reserved regions, if they overlap |
156 | * with /memory regions, insert_resource later on will take |
157 | * care of it. |
158 | */ |
159 | ret = add_kernel_resources(); |
160 | if (ret < 0) |
161 | goto error; |
162 | |
163 | #ifdef CONFIG_CRASH_DUMP |
164 | if (elfcorehdr_size > 0) { |
165 | elfcorehdr_res.start = elfcorehdr_addr; |
166 | elfcorehdr_res.end = elfcorehdr_addr + elfcorehdr_size - 1; |
167 | elfcorehdr_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
168 | add_resource(parent: &iomem_resource, res: &elfcorehdr_res); |
169 | } |
170 | #endif |
171 | |
172 | for_each_reserved_mem_region(region) { |
173 | res = &mem_res[res_idx--]; |
174 | |
175 | res->name = "Reserved" ; |
176 | res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; |
177 | res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); |
178 | res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; |
179 | |
180 | /* |
181 | * Ignore any other reserved regions within |
182 | * system memory. |
183 | */ |
184 | if (memblock_is_memory(addr: res->start)) { |
185 | /* Re-use this pre-allocated resource */ |
186 | res_idx++; |
187 | continue; |
188 | } |
189 | |
190 | ret = add_resource(parent: &iomem_resource, res); |
191 | if (ret < 0) |
192 | goto error; |
193 | } |
194 | |
195 | /* Add /memory regions to the resource tree */ |
196 | for_each_mem_region(region) { |
197 | res = &mem_res[res_idx--]; |
198 | |
199 | if (unlikely(memblock_is_nomap(region))) { |
200 | res->name = "Reserved" ; |
201 | res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; |
202 | } else { |
203 | res->name = "System RAM" ; |
204 | res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
205 | } |
206 | |
207 | res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); |
208 | res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; |
209 | |
210 | ret = add_resource(parent: &iomem_resource, res); |
211 | if (ret < 0) |
212 | goto error; |
213 | } |
214 | |
215 | /* Clean-up any unused pre-allocated resources */ |
216 | if (res_idx >= 0) |
217 | memblock_free(ptr: mem_res, size: (res_idx + 1) * sizeof(*mem_res)); |
218 | return; |
219 | |
220 | error: |
221 | /* Better an empty resource tree than an inconsistent one */ |
222 | release_child_resources(new: &iomem_resource); |
223 | memblock_free(ptr: mem_res, size: mem_res_sz); |
224 | } |
225 | |
226 | |
227 | static void __init parse_dtb(void) |
228 | { |
229 | /* Early scan of device tree from init memory */ |
230 | if (early_init_dt_scan(params: dtb_early_va)) { |
231 | const char *name = of_flat_dt_get_machine_name(); |
232 | |
233 | if (name) { |
234 | pr_info("Machine model: %s\n" , name); |
235 | dump_stack_set_arch_desc(fmt: "%s (DT)" , name); |
236 | } |
237 | } else { |
238 | pr_err("No DTB passed to the kernel\n" ); |
239 | } |
240 | |
241 | #ifdef CONFIG_CMDLINE_FORCE |
242 | strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); |
243 | pr_info("Forcing kernel command line to: %s\n" , boot_command_line); |
244 | #endif |
245 | } |
246 | |
247 | extern void __init init_rt_signal_env(void); |
248 | |
249 | void __init setup_arch(char **cmdline_p) |
250 | { |
251 | parse_dtb(); |
252 | setup_initial_init_mm(start_code: _stext, end_code: _etext, end_data: _edata, brk: _end); |
253 | |
254 | *cmdline_p = boot_command_line; |
255 | |
256 | early_ioremap_setup(); |
257 | sbi_init(); |
258 | jump_label_init(); |
259 | parse_early_param(); |
260 | |
261 | efi_init(); |
262 | paging_init(); |
263 | |
264 | /* Parse the ACPI tables for possible boot-time configuration */ |
265 | acpi_boot_table_init(); |
266 | |
267 | #if IS_ENABLED(CONFIG_BUILTIN_DTB) |
268 | unflatten_and_copy_device_tree(); |
269 | #else |
270 | unflatten_device_tree(); |
271 | #endif |
272 | misc_mem_init(); |
273 | |
274 | init_resources(); |
275 | |
276 | #ifdef CONFIG_KASAN |
277 | kasan_init(); |
278 | #endif |
279 | |
280 | #ifdef CONFIG_SMP |
281 | setup_smp(); |
282 | #endif |
283 | |
284 | if (!acpi_disabled) |
285 | acpi_init_rintc_map(); |
286 | |
287 | riscv_init_cbo_blocksizes(); |
288 | riscv_fill_hwcap(); |
289 | init_rt_signal_env(); |
290 | apply_boot_alternatives(); |
291 | |
292 | if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) && |
293 | riscv_isa_extension_available(NULL, ZICBOM)) |
294 | riscv_noncoherent_supported(); |
295 | riscv_set_dma_cache_alignment(); |
296 | |
297 | riscv_user_isa_enable(); |
298 | } |
299 | |
300 | bool arch_cpu_is_hotpluggable(int cpu) |
301 | { |
302 | return cpu_has_hotplug(cpu); |
303 | } |
304 | |
305 | void free_initmem(void) |
306 | { |
307 | if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) { |
308 | set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), set_memory_rw_nx); |
309 | if (IS_ENABLED(CONFIG_64BIT)) |
310 | set_kernel_memory(__init_begin, __init_end, set_memory_nx); |
311 | } |
312 | |
313 | free_initmem_default(POISON_FREE_INITMEM); |
314 | } |
315 | |
316 | static int dump_kernel_offset(struct notifier_block *self, |
317 | unsigned long v, void *p) |
318 | { |
319 | pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n" , |
320 | kernel_map.virt_offset, |
321 | KERNEL_LINK_ADDR); |
322 | |
323 | return 0; |
324 | } |
325 | |
326 | static struct notifier_block kernel_offset_notifier = { |
327 | .notifier_call = dump_kernel_offset |
328 | }; |
329 | |
330 | static int __init register_kernel_offset_dumper(void) |
331 | { |
332 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) |
333 | atomic_notifier_chain_register(nh: &panic_notifier_list, |
334 | nb: &kernel_offset_notifier); |
335 | |
336 | return 0; |
337 | } |
338 | device_initcall(register_kernel_offset_dumper); |
339 | |