e2ae634014
We have a handful of new kernel features for 5.11: * Support for the contiguous memory allocator. * Support for IRQ Time Accounting * Support for stack tracing * Support for strict /dev/mem * Support for kernel section protection I'm being a bit conservative on the cutoff for this round due to the timing, so this is all the new development I'm going to take for this cycle (even if some of it probably normally would have been OK). There are, however, some fixes on the list that I will likely be sending along either later this week or early next week. There is one issue in here: one of my test configurations (PREEMPT{,_DEBUG}=y) fails to boot on QEMU 5.0.0 (from April) as of the .text.init alignment patch. With any luck we'll sort out the issue, but given how many bugs get fixed all over the place and how unrelated those features seem my guess is that we're just running into something that's been lurking for a while and has already been fixed in the newer QEMU (though I wouldn't be surprised if it's one of these implicit assumptions we have in the boot flow). If it was hardware I'd be strongly inclined to look more closely, but given that users can upgrade their simulators I'm less worried about it. There are two merge conflicts, both in build files. They're both a bit clunky: arch/riscv/Kconfig is out of order (I have a script that's supposed to keep them in order, I'll fix it) and lib/Makefile is out of order (though GENERIC_LIB here doesn't mean quite what it does above). -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAl/cHO4THHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYiTlmD/4uDyNHBM1XH/XD4fSEwTYJvGLqt/Jo vtrGR/fm0SlQFUKCcywSzxcVAeGn56CACbEIDYLuL4xXRJmbwEuaRrHVx2sEhS9p pNhy+wus/SgDz5EUAawMyR2AEWgzl77hY5T/+AAo4yv65SGGBfsIdz5noIVwGNqW r0g5cw2O99z0vwu1aSrK4isWHconG9MfQnnVyepPSh67pyWS4aUCr1K3vLiqD2dE XcgtwdcgzUIY5aEoJNrWo5qTrcaG8m6MRNCDAKJ6MKdDA2wdGIN868G0wQnoURRm Y+yW7w3P20kM0b87zH50jujTWg38NBKOfaXb0mAfawZMapL60veTVmvs2kNtFXCy F6JWRkgTiRnGY72FtRR0igWXT5M7fz0EiLFXLMItGcgj79TUget4l/3sRMN47S/O cA/WiwptJH3mh8IkL6z5ZxWEThdOrbFt8F1T+Gyq/ayblcPnJaLn/wrWoeOwviWR fvEC7smuF5SBTbWZK5tBOP21Nvhb7bfr49Sgr8Tvdjl15tz97qK+2tsLXwkBoQnJ wU45jcXfzr5wgiGBOQANRite5bLsJ0TuOrTgA5gsGpv+JSDGbpcJbm0833x00nX/ 3GsW5xr+vsLCvljgPAtKsyDNRlGQu908Gxrat2+s8u92bLr1bwn30uKL5h6i/n1w QgWATuPPGXZZdw== =GWIH -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-5.11-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull RISC-V updates from Palmer Dabbelt: "We have a handful of new kernel features for 5.11: - Support for the contiguous memory allocator. - Support for IRQ Time Accounting - Support for stack tracing - Support for strict /dev/mem - Support for kernel section protection I'm being a bit conservative on the cutoff for this round due to the timing, so this is all the new development I'm going to take for this cycle (even if some of it probably normally would have been OK). There are, however, some fixes on the list that I will likely be sending along either later this week or early next week. There is one issue in here: one of my test configurations (PREEMPT{,_DEBUG}=y) fails to boot on QEMU 5.0.0 (from April) as of the .text.init alignment patch. With any luck we'll sort out the issue, but given how many bugs get fixed all over the place and how unrelated those features seem my guess is that we're just running into something that's been lurking for a while and has already been fixed in the newer QEMU (though I wouldn't be surprised if it's one of these implicit assumptions we have in the boot flow). If it was hardware I'd be strongly inclined to look more closely, but given that users can upgrade their simulators I'm less worried about it" * tag 'riscv-for-linus-5.11-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: arm64: Use the generic devmem_is_allowed() arm: Use the generic devmem_is_allowed() RISC-V: Use the new generic devmem_is_allowed() lib: Add a generic version of devmem_is_allowed() riscv: Fixed kernel test robot warning riscv: kernel: Drop unused clean rule riscv: provide memmove implementation RISC-V: Move dynamic relocation section under __init RISC-V: Protect all kernel sections including init early RISC-V: Align the .init.text section RISC-V: Initialize SBI early riscv: Enable ARCH_STACKWALK riscv: Make stack walk callback consistent with generic code riscv: Cleanup stacktrace riscv: Add HAVE_IRQ_TIME_ACCOUNTING riscv: Enable CMA support riscv: Ignore Image.* and loader.bin riscv: Clean up boot dir riscv: Fix compressed Image formats build RISC-V: Add kernel image sections to the resource tree
297 lines
7.2 KiB
C
297 lines
7.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
|
|
* Chen Liqin <liqin.chen@sunplusct.com>
|
|
* Lennox Wu <lennox.wu@sunplusct.com>
|
|
* Copyright (C) 2012 Regents of the University of California
|
|
* Copyright (C) 2020 FORTH-ICS/CARV
|
|
* Nick Kossifidis <mick@ics.forth.gr>
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/console.h>
|
|
#include <linux/screen_info.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/sched/task.h>
|
|
#include <linux/swiotlb.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/efi.h>
|
|
|
|
#include <asm/cpu_ops.h>
|
|
#include <asm/early_ioremap.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/set_memory.h>
|
|
#include <asm/sections.h>
|
|
#include <asm/sbi.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/thread_info.h>
|
|
#include <asm/kasan.h>
|
|
#include <asm/efi.h>
|
|
|
|
#include "head.h"
|
|
|
|
#if defined(CONFIG_DUMMY_CONSOLE) || defined(CONFIG_EFI)
|
|
struct screen_info screen_info __section(".data") = {
|
|
.orig_video_lines = 30,
|
|
.orig_video_cols = 80,
|
|
.orig_video_mode = 0,
|
|
.orig_video_ega_bx = 0,
|
|
.orig_video_isVGA = 1,
|
|
.orig_video_points = 8
|
|
};
|
|
#endif
|
|
|
|
/*
|
|
* The lucky hart to first increment this variable will boot the other cores.
|
|
* This is used before the kernel initializes the BSS so it can't be in the
|
|
* BSS.
|
|
*/
|
|
atomic_t hart_lottery __section(".sdata");
|
|
unsigned long boot_cpu_hartid;
|
|
static DEFINE_PER_CPU(struct cpu, cpu_devices);
|
|
|
|
/*
|
|
* Place kernel memory regions on the resource tree so that
|
|
* kexec-tools can retrieve them from /proc/iomem. While there
|
|
* also add "System RAM" regions for compatibility with other
|
|
* archs, and the rest of the known regions for completeness.
|
|
*/
|
|
static struct resource code_res = { .name = "Kernel code", };
|
|
static struct resource data_res = { .name = "Kernel data", };
|
|
static struct resource rodata_res = { .name = "Kernel rodata", };
|
|
static struct resource bss_res = { .name = "Kernel bss", };
|
|
|
|
static int __init add_resource(struct resource *parent,
|
|
struct resource *res)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = insert_resource(parent, res);
|
|
if (ret < 0) {
|
|
pr_err("Failed to add a %s resource at %llx\n",
|
|
res->name, (unsigned long long) res->start);
|
|
return ret;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int __init add_kernel_resources(struct resource *res)
|
|
{
|
|
int ret = 0;
|
|
|
|
/*
|
|
* The memory region of the kernel image is continuous and
|
|
* was reserved on setup_bootmem, find it here and register
|
|
* it as a resource, then register the various segments of
|
|
* the image as child nodes
|
|
*/
|
|
if (!(res->start <= code_res.start && res->end >= data_res.end))
|
|
return 0;
|
|
|
|
res->name = "Kernel image";
|
|
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
|
|
/*
|
|
* We removed a part of this region on setup_bootmem so
|
|
* we need to expand the resource for the bss to fit in.
|
|
*/
|
|
res->end = bss_res.end;
|
|
|
|
ret = add_resource(&iomem_resource, res);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = add_resource(res, &code_res);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = add_resource(res, &rodata_res);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = add_resource(res, &data_res);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = add_resource(res, &bss_res);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __init init_resources(void)
|
|
{
|
|
struct memblock_region *region = NULL;
|
|
struct resource *res = NULL;
|
|
int ret = 0;
|
|
|
|
code_res.start = __pa_symbol(_text);
|
|
code_res.end = __pa_symbol(_etext) - 1;
|
|
code_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
|
|
rodata_res.start = __pa_symbol(__start_rodata);
|
|
rodata_res.end = __pa_symbol(__end_rodata) - 1;
|
|
rodata_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
|
|
data_res.start = __pa_symbol(_data);
|
|
data_res.end = __pa_symbol(_edata) - 1;
|
|
data_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
|
|
bss_res.start = __pa_symbol(__bss_start);
|
|
bss_res.end = __pa_symbol(__bss_stop) - 1;
|
|
bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
|
|
/*
|
|
* Start by adding the reserved regions, if they overlap
|
|
* with /memory regions, insert_resource later on will take
|
|
* care of it.
|
|
*/
|
|
for_each_reserved_mem_region(region) {
|
|
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
|
|
if (!res)
|
|
panic("%s: Failed to allocate %zu bytes\n", __func__,
|
|
sizeof(struct resource));
|
|
|
|
res->name = "Reserved";
|
|
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
|
|
res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region));
|
|
res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1;
|
|
|
|
ret = add_kernel_resources(res);
|
|
if (ret < 0)
|
|
goto error;
|
|
else if (ret)
|
|
continue;
|
|
|
|
/*
|
|
* Ignore any other reserved regions within
|
|
* system memory.
|
|
*/
|
|
if (memblock_is_memory(res->start))
|
|
continue;
|
|
|
|
ret = add_resource(&iomem_resource, res);
|
|
if (ret < 0)
|
|
goto error;
|
|
}
|
|
|
|
/* Add /memory regions to the resource tree */
|
|
for_each_mem_region(region) {
|
|
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
|
|
if (!res)
|
|
panic("%s: Failed to allocate %zu bytes\n", __func__,
|
|
sizeof(struct resource));
|
|
|
|
if (unlikely(memblock_is_nomap(region))) {
|
|
res->name = "Reserved";
|
|
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
|
|
} else {
|
|
res->name = "System RAM";
|
|
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
|
}
|
|
|
|
res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
|
|
res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
|
|
|
|
ret = add_resource(&iomem_resource, res);
|
|
if (ret < 0)
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
memblock_free((phys_addr_t) res, sizeof(struct resource));
|
|
/* Better an empty resource tree than an inconsistent one */
|
|
release_child_resources(&iomem_resource);
|
|
}
|
|
|
|
|
|
static void __init parse_dtb(void)
|
|
{
|
|
/* Early scan of device tree from init memory */
|
|
if (early_init_dt_scan(dtb_early_va))
|
|
return;
|
|
|
|
pr_err("No DTB passed to the kernel\n");
|
|
#ifdef CONFIG_CMDLINE_FORCE
|
|
strlcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
|
pr_info("Forcing kernel command line to: %s\n", boot_command_line);
|
|
#endif
|
|
}
|
|
|
|
void __init setup_arch(char **cmdline_p)
|
|
{
|
|
parse_dtb();
|
|
init_mm.start_code = (unsigned long) _stext;
|
|
init_mm.end_code = (unsigned long) _etext;
|
|
init_mm.end_data = (unsigned long) _edata;
|
|
init_mm.brk = (unsigned long) _end;
|
|
|
|
*cmdline_p = boot_command_line;
|
|
|
|
early_ioremap_setup();
|
|
jump_label_init();
|
|
parse_early_param();
|
|
|
|
efi_init();
|
|
setup_bootmem();
|
|
paging_init();
|
|
init_resources();
|
|
#if IS_ENABLED(CONFIG_BUILTIN_DTB)
|
|
unflatten_and_copy_device_tree();
|
|
#else
|
|
if (early_init_dt_verify(__va(dtb_early_pa)))
|
|
unflatten_device_tree();
|
|
else
|
|
pr_err("No DTB found in kernel mappings\n");
|
|
#endif
|
|
|
|
if (IS_ENABLED(CONFIG_RISCV_SBI))
|
|
sbi_init();
|
|
|
|
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
|
protect_kernel_text_data();
|
|
#ifdef CONFIG_SWIOTLB
|
|
swiotlb_init(1);
|
|
#endif
|
|
|
|
#ifdef CONFIG_KASAN
|
|
kasan_init();
|
|
#endif
|
|
|
|
#ifdef CONFIG_SMP
|
|
setup_smp();
|
|
#endif
|
|
|
|
riscv_fill_hwcap();
|
|
}
|
|
|
|
static int __init topology_init(void)
|
|
{
|
|
int i;
|
|
|
|
for_each_possible_cpu(i) {
|
|
struct cpu *cpu = &per_cpu(cpu_devices, i);
|
|
|
|
cpu->hotpluggable = cpu_has_hotplug(i);
|
|
register_cpu(cpu, i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
subsys_initcall(topology_init);
|
|
|
|
void free_initmem(void)
|
|
{
|
|
unsigned long init_begin = (unsigned long)__init_begin;
|
|
unsigned long init_end = (unsigned long)__init_end;
|
|
|
|
set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
|
|
free_initmem_default(POISON_FREE_INITMEM);
|
|
}
|