Commit | Line | Data |
---|---|---|
588cb88c | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
76d2a049 PD |
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 | |
00ab027a NK |
7 | * Copyright (C) 2020 FORTH-ICS/CARV |
8 | * Nick Kossifidis <mick@ics.forth.gr> | |
76d2a049 PD |
9 | */ |
10 | ||
724f4c0d | 11 | #include <linux/acpi.h> |
a0418108 | 12 | #include <linux/cpu.h> |
76d2a049 PD |
13 | #include <linux/init.h> |
14 | #include <linux/mm.h> | |
15 | #include <linux/memblock.h> | |
16 | #include <linux/sched.h> | |
76d2a049 | 17 | #include <linux/console.h> |
76d2a049 | 18 | #include <linux/of_fdt.h> |
76d2a049 | 19 | #include <linux/sched/task.h> |
f1e58583 | 20 | #include <linux/smp.h> |
b91540d5 | 21 | #include <linux/efi.h> |
e53d2818 | 22 | #include <linux/crash_dump.h> |
54a519e6 | 23 | #include <linux/panic_notifier.h> |
76d2a049 | 24 | |
f9956119 | 25 | #include <asm/acpi.h> |
ffb0b0af | 26 | #include <asm/alternative.h> |
1631ba12 | 27 | #include <asm/cacheflush.h> |
43c16d51 | 28 | #include <asm/cpufeature.h> |
6262f661 | 29 | #include <asm/early_ioremap.h> |
44c92257 | 30 | #include <asm/pgtable.h> |
76d2a049 | 31 | #include <asm/setup.h> |
19a00869 | 32 | #include <asm/set_memory.h> |
76d2a049 | 33 | #include <asm/sections.h> |
b9dcd9e4 | 34 | #include <asm/sbi.h> |
76d2a049 PD |
35 | #include <asm/tlbflush.h> |
36 | #include <asm/thread_info.h> | |
8ad8b727 | 37 | #include <asm/kasan.h> |
b91540d5 | 38 | #include <asm/efi.h> |
76d2a049 | 39 | |
ffaee272 PW |
40 | #include "head.h" |
41 | ||
aff77833 ZL |
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 | */ | |
44c92257 VW |
47 | atomic_t hart_lottery __section(".sdata") |
48 | #ifdef CONFIG_XIP_KERNEL | |
49 | = ATOMIC_INIT(0xC001BEEF) | |
50 | #endif | |
51 | ; | |
f99fb607 | 52 | unsigned long boot_cpu_hartid; |
c5136add | 53 | EXPORT_SYMBOL_GPL(boot_cpu_hartid); |
76d2a049 | 54 | |
00ab027a NK |
55 | /* |
56 | * Place kernel memory regions on the resource tree so that | |
57 | * kexec-tools can retrieve them from /proc/iomem. While there | |
58 | * also add "System RAM" regions for compatibility with other | |
59 | * archs, and the rest of the known regions for completeness. | |
60 | */ | |
ffe0e526 | 61 | static struct resource kimage_res = { .name = "Kernel image", }; |
00ab027a NK |
62 | static struct resource code_res = { .name = "Kernel code", }; |
63 | static struct resource data_res = { .name = "Kernel data", }; | |
64 | static struct resource rodata_res = { .name = "Kernel rodata", }; | |
65 | static struct resource bss_res = { .name = "Kernel bss", }; | |
56409750 NK |
66 | #ifdef CONFIG_CRASH_DUMP |
67 | static struct resource elfcorehdr_res = { .name = "ELF Core hdr", }; | |
68 | #endif | |
00ab027a | 69 | |
e94eb7ea BT |
70 | static int num_standard_resources; |
71 | static struct resource *standard_resources; | |
72 | ||
00ab027a NK |
73 | static int __init add_resource(struct resource *parent, |
74 | struct resource *res) | |
75 | { | |
76 | int ret = 0; | |
77 | ||
78 | ret = insert_resource(parent, res); | |
79 | if (ret < 0) { | |
80 | pr_err("Failed to add a %s resource at %llx\n", | |
81 | res->name, (unsigned long long) res->start); | |
82 | return ret; | |
83 | } | |
84 | ||
85 | return 1; | |
86 | } | |
87 | ||
ffe0e526 | 88 | static int __init add_kernel_resources(void) |
00ab027a NK |
89 | { |
90 | int ret = 0; | |
91 | ||
92 | /* | |
93 | * The memory region of the kernel image is continuous and | |
ffe0e526 NK |
94 | * was reserved on setup_bootmem, register it here as a |
95 | * resource, with the various segments of the image as | |
96 | * child nodes. | |
00ab027a | 97 | */ |
00ab027a | 98 | |
ffe0e526 NK |
99 | code_res.start = __pa_symbol(_text); |
100 | code_res.end = __pa_symbol(_etext) - 1; | |
101 | code_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
00ab027a | 102 | |
ffe0e526 NK |
103 | rodata_res.start = __pa_symbol(__start_rodata); |
104 | rodata_res.end = __pa_symbol(__end_rodata) - 1; | |
105 | rodata_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
00ab027a | 106 | |
ffe0e526 NK |
107 | data_res.start = __pa_symbol(_data); |
108 | data_res.end = __pa_symbol(_edata) - 1; | |
109 | data_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
110 | ||
111 | bss_res.start = __pa_symbol(__bss_start); | |
112 | bss_res.end = __pa_symbol(__bss_stop) - 1; | |
113 | bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
114 | ||
115 | kimage_res.start = code_res.start; | |
116 | kimage_res.end = bss_res.end; | |
117 | kimage_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
118 | ||
119 | ret = add_resource(&iomem_resource, &kimage_res); | |
00ab027a NK |
120 | if (ret < 0) |
121 | return ret; | |
122 | ||
ffe0e526 | 123 | ret = add_resource(&kimage_res, &code_res); |
00ab027a NK |
124 | if (ret < 0) |
125 | return ret; | |
126 | ||
ffe0e526 | 127 | ret = add_resource(&kimage_res, &rodata_res); |
00ab027a NK |
128 | if (ret < 0) |
129 | return ret; | |
130 | ||
ffe0e526 | 131 | ret = add_resource(&kimage_res, &data_res); |
00ab027a NK |
132 | if (ret < 0) |
133 | return ret; | |
134 | ||
ffe0e526 | 135 | ret = add_resource(&kimage_res, &bss_res); |
00ab027a NK |
136 | |
137 | return ret; | |
138 | } | |
139 | ||
140 | static void __init init_resources(void) | |
141 | { | |
142 | struct memblock_region *region = NULL; | |
143 | struct resource *res = NULL; | |
797f0375 AP |
144 | struct resource *mem_res = NULL; |
145 | size_t mem_res_sz = 0; | |
e94eb7ea | 146 | int num_resources = 0, res_idx = 0, non_resv_res = 0; |
ffe0e526 | 147 | int ret = 0; |
00ab027a | 148 | |
ffe0e526 NK |
149 | /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ |
150 | num_resources = memblock.memory.cnt + memblock.reserved.cnt + 1; | |
151 | res_idx = num_resources - 1; | |
00ab027a | 152 | |
ffe0e526 | 153 | mem_res_sz = num_resources * sizeof(*mem_res); |
c6f23979 | 154 | mem_res = memblock_alloc_or_panic(mem_res_sz, SMP_CACHE_BYTES); |
ffe0e526 | 155 | |
00ab027a NK |
156 | /* |
157 | * Start by adding the reserved regions, if they overlap | |
158 | * with /memory regions, insert_resource later on will take | |
159 | * care of it. | |
160 | */ | |
ffe0e526 NK |
161 | ret = add_kernel_resources(); |
162 | if (ret < 0) | |
163 | goto error; | |
164 | ||
56409750 NK |
165 | #ifdef CONFIG_CRASH_DUMP |
166 | if (elfcorehdr_size > 0) { | |
167 | elfcorehdr_res.start = elfcorehdr_addr; | |
168 | elfcorehdr_res.end = elfcorehdr_addr + elfcorehdr_size - 1; | |
169 | elfcorehdr_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
170 | add_resource(&iomem_resource, &elfcorehdr_res); | |
171 | } | |
172 | #endif | |
173 | ||
00ab027a | 174 | for_each_reserved_mem_region(region) { |
ffe0e526 | 175 | res = &mem_res[res_idx--]; |
00ab027a NK |
176 | |
177 | res->name = "Reserved"; | |
e61bf5c0 | 178 | res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; |
00ab027a NK |
179 | res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); |
180 | res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; | |
181 | ||
00ab027a NK |
182 | /* |
183 | * Ignore any other reserved regions within | |
184 | * system memory. | |
185 | */ | |
797f0375 | 186 | if (memblock_is_memory(res->start)) { |
ffe0e526 NK |
187 | /* Re-use this pre-allocated resource */ |
188 | res_idx++; | |
00ab027a | 189 | continue; |
797f0375 | 190 | } |
00ab027a NK |
191 | |
192 | ret = add_resource(&iomem_resource, res); | |
193 | if (ret < 0) | |
194 | goto error; | |
195 | } | |
196 | ||
197 | /* Add /memory regions to the resource tree */ | |
198 | for_each_mem_region(region) { | |
ffe0e526 | 199 | res = &mem_res[res_idx--]; |
e94eb7ea | 200 | non_resv_res++; |
00ab027a NK |
201 | |
202 | if (unlikely(memblock_is_nomap(region))) { | |
203 | res->name = "Reserved"; | |
e61bf5c0 | 204 | res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; |
00ab027a NK |
205 | } else { |
206 | res->name = "System RAM"; | |
207 | res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
208 | } | |
209 | ||
210 | res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); | |
211 | res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; | |
212 | ||
213 | ret = add_resource(&iomem_resource, res); | |
214 | if (ret < 0) | |
215 | goto error; | |
216 | } | |
217 | ||
e94eb7ea BT |
218 | num_standard_resources = non_resv_res; |
219 | standard_resources = &mem_res[res_idx + 1]; | |
220 | ||
ffe0e526 | 221 | /* Clean-up any unused pre-allocated resources */ |
aa3e1ba3 | 222 | if (res_idx >= 0) |
4421cca0 | 223 | memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res)); |
00ab027a NK |
224 | return; |
225 | ||
226 | error: | |
00ab027a NK |
227 | /* Better an empty resource tree than an inconsistent one */ |
228 | release_child_resources(&iomem_resource); | |
4421cca0 | 229 | memblock_free(mem_res, mem_res_sz); |
00ab027a NK |
230 | } |
231 | ||
e94eb7ea BT |
232 | static int __init reserve_memblock_reserved_regions(void) |
233 | { | |
234 | u64 i, j; | |
235 | ||
236 | for (i = 0; i < num_standard_resources; i++) { | |
237 | struct resource *mem = &standard_resources[i]; | |
238 | phys_addr_t r_start, r_end, mem_size = resource_size(mem); | |
239 | ||
240 | if (!memblock_is_region_reserved(mem->start, mem_size)) | |
241 | continue; | |
242 | ||
243 | for_each_reserved_mem_range(j, &r_start, &r_end) { | |
244 | resource_size_t start, end; | |
245 | ||
246 | start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); | |
247 | end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); | |
248 | ||
249 | if (start > mem->end || end < mem->start) | |
250 | continue; | |
251 | ||
252 | reserve_region_with_split(mem, start, end, "Reserved"); | |
253 | } | |
254 | } | |
255 | ||
256 | return 0; | |
257 | } | |
258 | arch_initcall(reserve_memblock_reserved_regions); | |
00ab027a | 259 | |
8f3a2b4a | 260 | static void __init parse_dtb(void) |
76d2a049 | 261 | { |
8f3a2b4a | 262 | /* Early scan of device tree from init memory */ |
c796e187 | 263 | if (early_init_dt_scan(dtb_early_va, dtb_early_pa)) { |
46ad48e8 KW |
264 | const char *name = of_flat_dt_get_machine_name(); |
265 | ||
266 | if (name) { | |
267 | pr_info("Machine model: %s\n", name); | |
268 | dump_stack_set_arch_desc("%s (DT)", name); | |
269 | } | |
10f6913c WZ |
270 | } else { |
271 | pr_err("No DTB passed to the kernel\n"); | |
46ad48e8 | 272 | } |
76d2a049 PD |
273 | } |
274 | ||
ab83647f AG |
275 | #if defined(CONFIG_RISCV_COMBO_SPINLOCKS) |
276 | DEFINE_STATIC_KEY_TRUE(qspinlock_key); | |
277 | EXPORT_SYMBOL(qspinlock_key); | |
278 | #endif | |
279 | ||
280 | static void __init riscv_spinlock_init(void) | |
281 | { | |
282 | char *using_ext = NULL; | |
283 | ||
284 | if (IS_ENABLED(CONFIG_RISCV_TICKET_SPINLOCKS)) { | |
285 | pr_info("Ticket spinlock: enabled\n"); | |
286 | return; | |
287 | } | |
288 | ||
289 | if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && | |
290 | IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && | |
291 | riscv_isa_extension_available(NULL, ZABHA) && | |
292 | riscv_isa_extension_available(NULL, ZACAS)) { | |
293 | using_ext = "using Zabha"; | |
294 | } else if (riscv_isa_extension_available(NULL, ZICCRSE)) { | |
295 | using_ext = "using Ziccrse"; | |
296 | } | |
297 | #if defined(CONFIG_RISCV_COMBO_SPINLOCKS) | |
298 | else { | |
299 | static_branch_disable(&qspinlock_key); | |
300 | pr_info("Ticket spinlock: enabled\n"); | |
301 | return; | |
302 | } | |
303 | #endif | |
304 | ||
305 | if (!using_ext) | |
306 | pr_err("Queued spinlock without Zabha or Ziccrse"); | |
307 | else | |
308 | pr_info("Queued spinlock %s: enabled\n", using_ext); | |
309 | } | |
310 | ||
8ee0b418 GH |
311 | extern void __init init_rt_signal_env(void); |
312 | ||
76d2a049 PD |
313 | void __init setup_arch(char **cmdline_p) |
314 | { | |
8f3a2b4a | 315 | parse_dtb(); |
723a42f4 | 316 | setup_initial_init_mm(_stext, _etext, _edata, _end); |
76d2a049 | 317 | |
680f9b8e AP |
318 | *cmdline_p = boot_command_line; |
319 | ||
6262f661 | 320 | early_ioremap_setup(); |
24fc1808 | 321 | sbi_init(); |
6134b110 | 322 | jump_label_init(); |
680f9b8e AP |
323 | parse_early_param(); |
324 | ||
b91540d5 | 325 | efi_init(); |
76d2a049 | 326 | paging_init(); |
724f4c0d S |
327 | |
328 | /* Parse the ACPI tables for possible boot-time configuration */ | |
329 | acpi_boot_table_init(); | |
330 | ||
2d268251 PD |
331 | #if IS_ENABLED(CONFIG_BUILTIN_DTB) |
332 | unflatten_and_copy_device_tree(); | |
333 | #else | |
f1581626 | 334 | unflatten_device_tree(); |
2d268251 | 335 | #endif |
cbd34f4b | 336 | misc_mem_init(); |
51858aaf | 337 | |
e53d2818 | 338 | init_resources(); |
62149f35 | 339 | |
8ad8b727 NH |
340 | #ifdef CONFIG_KASAN |
341 | kasan_init(); | |
342 | #endif | |
343 | ||
76d2a049 PD |
344 | #ifdef CONFIG_SMP |
345 | setup_smp(); | |
346 | #endif | |
347 | ||
eabd9db6 | 348 | if (!acpi_disabled) { |
f9956119 | 349 | acpi_init_rintc_map(); |
eabd9db6 HX |
350 | acpi_map_cpus_to_nodes(); |
351 | } | |
f9956119 | 352 | |
7ea5a736 | 353 | riscv_init_cbo_blocksizes(); |
8f7e001e | 354 | riscv_fill_hwcap(); |
ffb0b0af | 355 | apply_boot_alternatives(); |
564fc8eb | 356 | init_rt_signal_env(); |
43c16d51 | 357 | |
abcc445a JZ |
358 | if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) && |
359 | riscv_isa_extension_available(NULL, ZICBOM)) | |
360 | riscv_noncoherent_supported(); | |
29267151 | 361 | riscv_set_dma_cache_alignment(); |
43c16d51 AJ |
362 | |
363 | riscv_user_isa_enable(); | |
ab83647f | 364 | riscv_spinlock_init(); |
76d2a049 | 365 | } |
f1e58583 | 366 | |
00bf4641 | 367 | bool arch_cpu_is_hotpluggable(int cpu) |
f1e58583 | 368 | { |
00bf4641 | 369 | return cpu_has_hotplug(cpu); |
f1e58583 | 370 | } |
19a00869 AP |
371 | |
372 | void free_initmem(void) | |
373 | { | |
6fdd5d2f BT |
374 | if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) { |
375 | set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), set_memory_rw_nx); | |
376 | if (IS_ENABLED(CONFIG_64BIT)) | |
377 | set_kernel_memory(__init_begin, __init_end, set_memory_nx); | |
378 | } | |
f105ea98 | 379 | |
19a00869 AP |
380 | free_initmem_default(POISON_FREE_INITMEM); |
381 | } | |
54a519e6 AG |
382 | |
383 | static int dump_kernel_offset(struct notifier_block *self, | |
384 | unsigned long v, void *p) | |
385 | { | |
386 | pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n", | |
387 | kernel_map.virt_offset, | |
388 | KERNEL_LINK_ADDR); | |
389 | ||
390 | return 0; | |
391 | } | |
392 | ||
393 | static struct notifier_block kernel_offset_notifier = { | |
394 | .notifier_call = dump_kernel_offset | |
395 | }; | |
396 | ||
397 | static int __init register_kernel_offset_dumper(void) | |
398 | { | |
399 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) | |
400 | atomic_notifier_chain_register(&panic_notifier_list, | |
401 | &kernel_offset_notifier); | |
402 | ||
403 | return 0; | |
404 | } | |
405 | device_initcall(register_kernel_offset_dumper); |