2022-05-31 18:04:11 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
|
|
|
|
*
|
|
|
|
* Derived from MIPS:
|
|
|
|
* Copyright (C) 1995 Linus Torvalds
|
|
|
|
* Copyright (C) 1995 Waldorf Electronics
|
|
|
|
* Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Ralf Baechle
|
|
|
|
* Copyright (C) 1996 Stoned Elipot
|
|
|
|
* Copyright (C) 1999 Silicon Graphics, Inc.
|
|
|
|
* Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki
|
|
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/acpi.h>
|
|
|
|
#include <linux/dmi.h>
|
|
|
|
#include <linux/efi.h>
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/screen_info.h>
|
|
|
|
#include <linux/memblock.h>
|
|
|
|
#include <linux/initrd.h>
|
|
|
|
#include <linux/ioport.h>
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
#include <linux/kexec.h>
|
|
|
|
#include <linux/crash_dump.h>
|
2022-05-31 18:04:11 +08:00
|
|
|
#include <linux/root_dev.h>
|
|
|
|
#include <linux/console.h>
|
|
|
|
#include <linux/pfn.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/sizes.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/dma-map-ops.h>
|
2022-12-10 22:40:05 +08:00
|
|
|
#include <linux/libfdt.h>
|
|
|
|
#include <linux/of_fdt.h>
|
|
|
|
#include <linux/of_address.h>
|
2022-12-10 22:40:15 +08:00
|
|
|
#include <linux/suspend.h>
|
2022-05-31 18:04:11 +08:00
|
|
|
#include <linux/swiotlb.h>
|
|
|
|
|
|
|
|
#include <asm/addrspace.h>
|
2022-12-10 22:39:59 +08:00
|
|
|
#include <asm/alternative.h>
|
2022-05-31 18:04:11 +08:00
|
|
|
#include <asm/bootinfo.h>
|
2022-12-10 22:39:59 +08:00
|
|
|
#include <asm/bugs.h>
|
2022-05-31 18:04:11 +08:00
|
|
|
#include <asm/cache.h>
|
|
|
|
#include <asm/cpu.h>
|
|
|
|
#include <asm/dma.h>
|
|
|
|
#include <asm/efi.h>
|
|
|
|
#include <asm/loongson.h>
|
2022-05-31 18:04:12 +08:00
|
|
|
#include <asm/numa.h>
|
2022-05-31 18:04:11 +08:00
|
|
|
#include <asm/pgalloc.h>
|
|
|
|
#include <asm/sections.h>
|
|
|
|
#include <asm/setup.h>
|
|
|
|
#include <asm/time.h>
|
|
|
|
|
|
|
|
#define SMBIOS_BIOSSIZE_OFFSET 0x09
|
|
|
|
#define SMBIOS_BIOSEXTERN_OFFSET 0x13
|
|
|
|
#define SMBIOS_FREQLOW_OFFSET 0x16
|
|
|
|
#define SMBIOS_FREQHIGH_OFFSET 0x17
|
|
|
|
#define SMBIOS_FREQLOW_MASK 0xFF
|
|
|
|
#define SMBIOS_CORE_PACKAGE_OFFSET 0x23
|
|
|
|
#define LOONGSON_EFI_ENABLE (1 << 3)
|
|
|
|
|
efi/loongarch: Add efistub booting support
This patch adds efistub booting support, which is the standard UEFI boot
protocol for LoongArch to use.
We use generic efistub, which means we can pass boot information (i.e.,
system table, memory map, kernel command line, initrd) via a light FDT
and drop a lot of non-standard code.
We use a flat mapping to map the efi runtime in the kernel's address
space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
flat mapping is not identity mapping, SetVirtualAddressMap() is still
needed for the efi runtime.
Tested-by: Xi Ruoyao <xry111@xry111.site>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
[ardb: change fpic to fpie as suggested by Xi Ruoyao]
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
2022-08-19 18:20:37 +08:00
|
|
|
struct screen_info screen_info __section(".data");
|
2022-05-31 18:04:11 +08:00
|
|
|
|
efi/loongarch: libstub: remove dependency on flattened DT
LoongArch does not use FDT or DT natively [yet], and the only reason it
currently uses it is so that it can reuse the existing EFI stub code.
Overloading the DT with data passed between the EFI stub and the core
kernel has been a source of problems: there is the overlap between
information provided by EFI which DT can also provide (initrd base/size,
command line, memory descriptions), requiring us to reason about which
is which and what to prioritize. It has also resulted in ABI leaks,
i.e., internal ABI being promoted to external ABI inadvertently because
the bootloader can set the EFI stub's DT properties as well (e.g.,
"kaslr-seed"). This has become especially problematic with boot
environments that want to pretend that EFI boot is being done (to access
ACPI and SMBIOS tables, for instance) but have no ability to execute the
EFI stub, and so the environment that the EFI stub creates is emulated
[poorly, in some cases].
Another downside of treating DT like this is that the DT binary that the
kernel receives is different from the one created by the firmware, which
is undesirable in the context of secure and measured boot.
Given that LoongArch support in Linux is brand new, we can avoid these
pitfalls, and treat the DT strictly as a hardware description, and use a
separate handover method between the EFI stub and the kernel. Now that
initrd loading and passing the EFI memory map have been refactored into
pure EFI routines that use EFI configuration tables, the only thing we
need to pass directly is the kernel command line (even if we could pass
this via a config table as well, it is used extremely early, so passing
it directly is preferred in this case.)
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
2022-09-17 01:48:53 +08:00
|
|
|
unsigned long fw_arg0, fw_arg1, fw_arg2;
|
2022-05-31 18:04:11 +08:00
|
|
|
DEFINE_PER_CPU(unsigned long, kernelsp);
|
|
|
|
struct cpuinfo_loongarch cpu_data[NR_CPUS] __read_mostly;
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(cpu_data);
|
|
|
|
|
|
|
|
struct loongson_board_info b_info;
|
|
|
|
static const char dmi_empty_string[] = " ";
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup information
|
|
|
|
*
|
|
|
|
* These are initialized so they are in the .data section
|
|
|
|
*/
|
2022-12-10 22:40:05 +08:00
|
|
|
char init_command_line[COMMAND_LINE_SIZE] __initdata;
|
2022-05-31 18:04:11 +08:00
|
|
|
|
|
|
|
static int num_standard_resources;
|
|
|
|
static struct resource *standard_resources;
|
|
|
|
|
|
|
|
static struct resource code_resource = { .name = "Kernel code", };
|
|
|
|
static struct resource data_resource = { .name = "Kernel data", };
|
|
|
|
static struct resource bss_resource = { .name = "Kernel bss", };
|
|
|
|
|
|
|
|
const char *get_system_type(void)
|
|
|
|
{
|
|
|
|
return "generic-loongson-machine";
|
|
|
|
}
|
|
|
|
|
2022-12-10 22:39:59 +08:00
|
|
|
void __init check_bugs(void)
|
|
|
|
{
|
|
|
|
alternative_instructions();
|
|
|
|
}
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
static const char *dmi_string_parse(const struct dmi_header *dm, u8 s)
|
|
|
|
{
|
|
|
|
const u8 *bp = ((u8 *) dm) + dm->length;
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
s--;
|
|
|
|
while (s > 0 && *bp) {
|
|
|
|
bp += strlen(bp) + 1;
|
|
|
|
s--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*bp != 0) {
|
|
|
|
size_t len = strlen(bp)+1;
|
|
|
|
size_t cmp_len = len > 8 ? 8 : len;
|
|
|
|
|
|
|
|
if (!memcmp(bp, dmi_empty_string, cmp_len))
|
|
|
|
return dmi_empty_string;
|
|
|
|
|
|
|
|
return bp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init parse_cpu_table(const struct dmi_header *dm)
|
|
|
|
{
|
|
|
|
long freq_temp = 0;
|
|
|
|
char *dmi_data = (char *)dm;
|
|
|
|
|
|
|
|
freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) +
|
|
|
|
((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK));
|
|
|
|
cpu_clock_freq = freq_temp * 1000000;
|
|
|
|
|
|
|
|
loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
|
|
|
|
loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET);
|
|
|
|
|
|
|
|
pr_info("CpuClock = %llu\n", cpu_clock_freq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init parse_bios_table(const struct dmi_header *dm)
|
|
|
|
{
|
|
|
|
char *dmi_data = (char *)dm;
|
|
|
|
|
2022-07-21 17:53:01 +08:00
|
|
|
b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
|
2022-05-31 18:04:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __init find_tokens(const struct dmi_header *dm, void *dummy)
|
|
|
|
{
|
|
|
|
switch (dm->type) {
|
|
|
|
case 0x0: /* Extern BIOS */
|
|
|
|
parse_bios_table(dm);
|
|
|
|
break;
|
|
|
|
case 0x4: /* Calling interface */
|
|
|
|
parse_cpu_table(dm);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void __init smbios_parse(void)
|
|
|
|
{
|
|
|
|
b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
|
|
|
|
b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION);
|
|
|
|
b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE);
|
|
|
|
b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR);
|
|
|
|
b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME);
|
|
|
|
dmi_walk(find_tokens, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usermem __initdata;
|
|
|
|
|
|
|
|
static int __init early_parse_mem(char *p)
|
|
|
|
{
|
|
|
|
phys_addr_t start, size;
|
|
|
|
|
|
|
|
if (!p) {
|
|
|
|
pr_err("mem parameter is empty, do nothing\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a user specifies memory size, we
|
|
|
|
* blow away any automatically generated
|
|
|
|
* size.
|
|
|
|
*/
|
|
|
|
if (usermem == 0) {
|
|
|
|
usermem = 1;
|
|
|
|
memblock_remove(memblock_start_of_DRAM(),
|
|
|
|
memblock_end_of_DRAM() - memblock_start_of_DRAM());
|
|
|
|
}
|
|
|
|
start = 0;
|
|
|
|
size = memparse(p, &p);
|
|
|
|
if (*p == '@')
|
|
|
|
start = memparse(p + 1, &p);
|
|
|
|
else {
|
|
|
|
pr_err("Invalid format!\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-05-31 18:04:12 +08:00
|
|
|
if (!IS_ENABLED(CONFIG_NUMA))
|
|
|
|
memblock_add(start, size);
|
|
|
|
else
|
|
|
|
memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE);
|
2022-05-31 18:04:11 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
early_param("mem", early_parse_mem);
|
|
|
|
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
static void __init arch_reserve_vmcore(void)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_PROC_VMCORE
|
|
|
|
u64 i;
|
|
|
|
phys_addr_t start, end;
|
|
|
|
|
|
|
|
if (!is_kdump_kernel())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!elfcorehdr_size) {
|
|
|
|
for_each_mem_range(i, &start, &end) {
|
|
|
|
if (elfcorehdr_addr >= start && elfcorehdr_addr < end) {
|
|
|
|
/*
|
|
|
|
* Reserve from the elf core header to the end of
|
|
|
|
* the memory segment, that should all be kdump
|
|
|
|
* reserved memory.
|
|
|
|
*/
|
|
|
|
elfcorehdr_size = end - elfcorehdr_addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
|
|
|
|
pr_warn("elfcorehdr is overlapped\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
|
|
|
|
|
|
|
|
pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n",
|
|
|
|
elfcorehdr_size >> 10, elfcorehdr_addr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init arch_parse_crashkernel(void)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
|
|
int ret;
|
|
|
|
unsigned long long start;
|
|
|
|
unsigned long long total_mem;
|
|
|
|
unsigned long long crash_base, crash_size;
|
|
|
|
|
|
|
|
total_mem = memblock_phys_mem_size();
|
|
|
|
ret = parse_crashkernel(boot_command_line, total_mem, &crash_size, &crash_base);
|
|
|
|
if (ret < 0 || crash_size <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
start = memblock_phys_alloc_range(crash_size, 1, crash_base, crash_base + crash_size);
|
|
|
|
if (start != crash_base) {
|
|
|
|
pr_warn("Invalid memory region reserved for crash kernel\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
crashk_res.start = crash_base;
|
|
|
|
crashk_res.end = crash_base + crash_size - 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-12-10 22:40:05 +08:00
|
|
|
static void __init fdt_setup(void)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_OF_EARLY_FLATTREE
|
|
|
|
void *fdt_pointer;
|
|
|
|
|
|
|
|
/* ACPI-based systems do not require parsing fdt */
|
|
|
|
if (acpi_os_get_root_pointer())
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Look for a device tree configuration table entry */
|
|
|
|
fdt_pointer = efi_fdt_pointer();
|
|
|
|
if (!fdt_pointer || fdt_check_header(fdt_pointer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
early_init_dt_scan(fdt_pointer);
|
|
|
|
early_init_fdt_reserve_self();
|
|
|
|
|
|
|
|
max_low_pfn = PFN_PHYS(memblock_end_of_DRAM());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init bootcmdline_init(char **cmdline_p)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If CONFIG_CMDLINE_FORCE is enabled then initializing the command line
|
|
|
|
* is trivial - we simply use the built-in command line unconditionally &
|
|
|
|
* unmodified.
|
|
|
|
*/
|
|
|
|
if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
|
|
|
|
strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_OF_FLATTREE
|
|
|
|
/*
|
|
|
|
* If CONFIG_CMDLINE_BOOTLOADER is enabled and we are in FDT-based system,
|
|
|
|
* the boot_command_line will be overwritten by early_init_dt_scan_chosen().
|
|
|
|
* So we need to append init_command_line (the original copy of boot_command_line)
|
|
|
|
* to boot_command_line.
|
|
|
|
*/
|
|
|
|
if (initial_boot_params) {
|
|
|
|
if (boot_command_line[0])
|
|
|
|
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
|
|
|
|
|
|
|
|
strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
out:
|
|
|
|
*cmdline_p = boot_command_line;
|
|
|
|
}
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
void __init platform_init(void)
|
|
|
|
{
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
arch_reserve_vmcore();
|
|
|
|
arch_parse_crashkernel();
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
#ifdef CONFIG_ACPI_TABLE_UPGRADE
|
|
|
|
acpi_table_upgrade();
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_ACPI
|
|
|
|
acpi_gbl_use_default_register_widths = false;
|
|
|
|
acpi_boot_table_init();
|
|
|
|
#endif
|
2022-12-10 22:40:05 +08:00
|
|
|
unflatten_and_copy_device_tree();
|
2022-05-31 18:04:11 +08:00
|
|
|
|
2022-05-31 18:04:12 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
|
|
|
init_numa_memory();
|
|
|
|
#endif
|
2022-05-31 18:04:11 +08:00
|
|
|
dmi_setup();
|
|
|
|
smbios_parse();
|
|
|
|
pr_info("The BIOS Version: %s\n", b_info.bios_version);
|
|
|
|
|
|
|
|
efi_runtime_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init check_kernel_sections_mem(void)
|
|
|
|
{
|
|
|
|
phys_addr_t start = __pa_symbol(&_text);
|
|
|
|
phys_addr_t size = __pa_symbol(&_end) - start;
|
|
|
|
|
|
|
|
if (!memblock_is_region_memory(start, size)) {
|
|
|
|
pr_info("Kernel sections are not in the memory maps\n");
|
|
|
|
memblock_add(start, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* arch_mem_init - initialize memory management subsystem
|
|
|
|
*/
|
|
|
|
static void __init arch_mem_init(char **cmdline_p)
|
|
|
|
{
|
|
|
|
if (usermem)
|
|
|
|
pr_info("User-defined physical RAM map overwrite\n");
|
|
|
|
|
|
|
|
check_kernel_sections_mem();
|
|
|
|
|
2022-12-10 22:40:05 +08:00
|
|
|
early_init_fdt_scan_reserved_mem();
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
/*
|
|
|
|
* In order to reduce the possibility of kernel panic when failed to
|
|
|
|
* get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
|
|
|
|
* low memory as small as possible before plat_swiotlb_setup(), so
|
|
|
|
* make sparse_init() using top-down allocation.
|
|
|
|
*/
|
|
|
|
memblock_set_bottom_up(false);
|
|
|
|
sparse_init();
|
|
|
|
memblock_set_bottom_up(true);
|
|
|
|
|
LoongArch: Use acpi_arch_dma_setup() and remove ARCH_HAS_PHYS_TO_DMA
Use _DMA defined in ACPI spec for translation between
DMA address and CPU address, and implement acpi_arch_dma_setup
for initializing dev->dma_range_map, where acpi_dma_get_range
is called for parsing _DMA.
e.g.
If we have two dma ranges:
cpu address dma address size offset
0x200080000000 0x2080000000 0x400000000 0x1fe000000000
0x400080000000 0x4080000000 0x400000000 0x3fc000000000
_DMA for pci devices should be declared in host bridge as
flowing:
Name (_DMA, ResourceTemplate() {
QWordMemory (ResourceProducer,
PosDecode,
MinFixed,
MaxFixed,
NonCacheable,
ReadWrite,
0x0,
0x4080000000,
0x447fffffff,
0x3fc000000000,
0x400000000,
,
,
)
QWordMemory (ResourceProducer,
PosDecode,
MinFixed,
MaxFixed,
NonCacheable,
ReadWrite,
0x0,
0x2080000000,
0x247fffffff,
0x1fe000000000,
0x400000000,
,
,
)
})
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2022-09-11 17:06:35 +08:00
|
|
|
swiotlb_init(true, SWIOTLB_VERBOSE);
|
2022-05-31 18:04:11 +08:00
|
|
|
|
|
|
|
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
|
|
|
|
|
2022-12-10 22:40:15 +08:00
|
|
|
/* Reserve for hibernation. */
|
|
|
|
register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)),
|
|
|
|
PFN_UP(__pa_symbol(&__nosave_end)));
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
memblock_dump_all();
|
|
|
|
|
|
|
|
early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init resource_init(void)
|
|
|
|
{
|
|
|
|
long i = 0;
|
|
|
|
size_t res_size;
|
|
|
|
struct resource *res;
|
|
|
|
struct memblock_region *region;
|
|
|
|
|
|
|
|
code_resource.start = __pa_symbol(&_text);
|
|
|
|
code_resource.end = __pa_symbol(&_etext) - 1;
|
|
|
|
data_resource.start = __pa_symbol(&_etext);
|
|
|
|
data_resource.end = __pa_symbol(&_edata) - 1;
|
|
|
|
bss_resource.start = __pa_symbol(&__bss_start);
|
|
|
|
bss_resource.end = __pa_symbol(&__bss_stop) - 1;
|
|
|
|
|
|
|
|
num_standard_resources = memblock.memory.cnt;
|
|
|
|
res_size = num_standard_resources * sizeof(*standard_resources);
|
|
|
|
standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES);
|
|
|
|
|
|
|
|
for_each_mem_region(region) {
|
|
|
|
res = &standard_resources[i++];
|
|
|
|
if (!memblock_is_nomap(region)) {
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
res->name = "Reserved";
|
|
|
|
res->flags = IORESOURCE_MEM;
|
|
|
|
res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region));
|
|
|
|
res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
request_resource(&iomem_resource, res);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't know which RAM region contains kernel data,
|
|
|
|
* so we try it repeatedly and let the resource manager
|
|
|
|
* test it.
|
|
|
|
*/
|
|
|
|
request_resource(res, &code_resource);
|
|
|
|
request_resource(res, &data_resource);
|
|
|
|
request_resource(res, &bss_resource);
|
|
|
|
}
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
|
|
if (crashk_res.start < crashk_res.end) {
|
|
|
|
insert_resource(&iomem_resource, &crashk_res);
|
|
|
|
pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
|
|
|
|
(unsigned long)((crashk_res.end - crashk_res.start + 1) >> 20),
|
|
|
|
(unsigned long)(crashk_res.start >> 20));
|
|
|
|
}
|
|
|
|
#endif
|
2022-05-31 18:04:11 +08:00
|
|
|
}
|
|
|
|
|
2022-12-10 22:40:05 +08:00
|
|
|
static int __init add_legacy_isa_io(struct fwnode_handle *fwnode,
|
|
|
|
resource_size_t hw_start, resource_size_t size)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
unsigned long vaddr;
|
|
|
|
struct logic_pio_hwaddr *range;
|
|
|
|
|
|
|
|
range = kzalloc(sizeof(*range), GFP_ATOMIC);
|
|
|
|
if (!range)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
range->fwnode = fwnode;
|
|
|
|
range->size = size = round_up(size, PAGE_SIZE);
|
|
|
|
range->hw_start = hw_start;
|
|
|
|
range->flags = LOGIC_PIO_CPU_MMIO;
|
|
|
|
|
|
|
|
ret = logic_pio_register_range(range);
|
|
|
|
if (ret) {
|
|
|
|
kfree(range);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Legacy ISA must placed at the start of PCI_IOBASE */
|
|
|
|
if (range->io_start != 0) {
|
|
|
|
logic_pio_unregister_range(range);
|
|
|
|
kfree(range);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vaddr = (unsigned long)(PCI_IOBASE + range->io_start);
|
|
|
|
ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __init int arch_reserve_pio_range(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
|
|
|
|
for_each_node_by_name(np, "isa") {
|
|
|
|
struct of_range range;
|
|
|
|
struct of_range_parser parser;
|
|
|
|
|
|
|
|
pr_info("ISA Bridge: %pOF\n", np);
|
|
|
|
|
|
|
|
if (of_range_parser_init(&parser, np)) {
|
|
|
|
pr_info("Failed to parse resources.\n");
|
|
|
|
of_node_put(np);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for_each_of_range(&parser, &range) {
|
|
|
|
switch (range.flags & IORESOURCE_TYPE_BITS) {
|
|
|
|
case IORESOURCE_IO:
|
|
|
|
pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
|
|
|
|
range.cpu_addr,
|
|
|
|
range.cpu_addr + range.size - 1,
|
|
|
|
range.bus_addr);
|
|
|
|
if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size))
|
|
|
|
pr_warn("Failed to reserve legacy IO in Logic PIO\n");
|
|
|
|
break;
|
|
|
|
case IORESOURCE_MEM:
|
|
|
|
pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
|
|
|
|
range.cpu_addr,
|
|
|
|
range.cpu_addr + range.size - 1,
|
|
|
|
range.bus_addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
arch_initcall(arch_reserve_pio_range);
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
static int __init reserve_memblock_reserved_regions(void)
|
|
|
|
{
|
|
|
|
u64 i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < num_standard_resources; ++i) {
|
|
|
|
struct resource *mem = &standard_resources[i];
|
|
|
|
phys_addr_t r_start, r_end, mem_size = resource_size(mem);
|
|
|
|
|
|
|
|
if (!memblock_is_region_reserved(mem->start, mem_size))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for_each_reserved_mem_range(j, &r_start, &r_end) {
|
|
|
|
resource_size_t start, end;
|
|
|
|
|
|
|
|
start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start);
|
|
|
|
end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end);
|
|
|
|
|
|
|
|
if (start > mem->end || end < mem->start)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
reserve_region_with_split(mem, start, end, "Reserved");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
arch_initcall(reserve_memblock_reserved_regions);
|
|
|
|
|
2022-05-31 18:04:12 +08:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
static void __init prefill_possible_map(void)
|
|
|
|
{
|
|
|
|
int i, possible;
|
|
|
|
|
|
|
|
possible = num_processors + disabled_cpus;
|
|
|
|
if (possible > nr_cpu_ids)
|
|
|
|
possible = nr_cpu_ids;
|
|
|
|
|
|
|
|
pr_info("SMP: Allowing %d CPUs, %d hotplug CPUs\n",
|
|
|
|
possible, max((possible - num_processors), 0));
|
|
|
|
|
|
|
|
for (i = 0; i < possible; i++)
|
|
|
|
set_cpu_possible(i, true);
|
|
|
|
for (; i < NR_CPUS; i++)
|
|
|
|
set_cpu_possible(i, false);
|
|
|
|
|
2022-09-06 07:08:17 +08:00
|
|
|
set_nr_cpu_ids(possible);
|
2022-05-31 18:04:12 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-05-31 18:04:11 +08:00
|
|
|
void __init setup_arch(char **cmdline_p)
|
|
|
|
{
|
|
|
|
cpu_probe();
|
|
|
|
|
|
|
|
init_environ();
|
efi/loongarch: libstub: remove dependency on flattened DT
LoongArch does not use FDT or DT natively [yet], and the only reason it
currently uses it is so that it can reuse the existing EFI stub code.
Overloading the DT with data passed between the EFI stub and the core
kernel has been a source of problems: there is the overlap between
information provided by EFI which DT can also provide (initrd base/size,
command line, memory descriptions), requiring us to reason about which
is which and what to prioritize. It has also resulted in ABI leaks,
i.e., internal ABI being promoted to external ABI inadvertently because
the bootloader can set the EFI stub's DT properties as well (e.g.,
"kaslr-seed"). This has become especially problematic with boot
environments that want to pretend that EFI boot is being done (to access
ACPI and SMBIOS tables, for instance) but have no ability to execute the
EFI stub, and so the environment that the EFI stub creates is emulated
[poorly, in some cases].
Another downside of treating DT like this is that the DT binary that the
kernel receives is different from the one created by the firmware, which
is undesirable in the context of secure and measured boot.
Given that LoongArch support in Linux is brand new, we can avoid these
pitfalls, and treat the DT strictly as a hardware description, and use a
separate handover method between the EFI stub and the kernel. Now that
initrd loading and passing the EFI memory map have been refactored into
pure EFI routines that use EFI configuration tables, the only thing we
need to pass directly is the kernel command line (even if we could pass
this via a config table as well, it is used extremely early, so passing
it directly is preferred in this case.)
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
2022-09-17 01:48:53 +08:00
|
|
|
efi_init();
|
2022-12-10 22:40:05 +08:00
|
|
|
fdt_setup();
|
2022-05-31 18:04:11 +08:00
|
|
|
memblock_init();
|
2022-10-12 16:36:14 +08:00
|
|
|
pagetable_init();
|
2022-12-10 22:40:05 +08:00
|
|
|
bootcmdline_init(cmdline_p);
|
2022-05-31 18:04:11 +08:00
|
|
|
parse_early_param();
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
reserve_initrd_mem();
|
2022-05-31 18:04:11 +08:00
|
|
|
|
|
|
|
platform_init();
|
|
|
|
arch_mem_init(cmdline_p);
|
|
|
|
|
|
|
|
resource_init();
|
LoongArch: Fix the !CONFIG_SMP build
1, We assume arch/loongarch/include/asm/smp.h be included in include/
linux/smp.h is valid and the reverse inclusion isn't. So remove the
<linux/smp.h> in arch/loongarch/include/asm/smp.h.
2, arch/loongarch/include/asm/smp.h is only needed when CONFIG_SMP,
and setup.c include it only because it need plat_smp_setup(). So,
reorganize setup.c & smp.h, and then remove <asm/smp.h> in setup.c.
3, Fix cacheinfo.c and percpu.h build error by adding the missing header
files when !CONFIG_SMP.
4, Fix acpi.c build error by adding CONFIG_SMP guards.
5, Move irq_stat definition from smp.c to irq.c and fix its declaration.
6, Select CONFIG_SMP for CONFIG_NUMA, similar as other architectures do.
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-06-05 16:19:53 +08:00
|
|
|
#ifdef CONFIG_SMP
|
2022-05-31 18:04:12 +08:00
|
|
|
plat_smp_setup();
|
|
|
|
prefill_possible_map();
|
LoongArch: Fix the !CONFIG_SMP build
1, We assume arch/loongarch/include/asm/smp.h be included in include/
linux/smp.h is valid and the reverse inclusion isn't. So remove the
<linux/smp.h> in arch/loongarch/include/asm/smp.h.
2, arch/loongarch/include/asm/smp.h is only needed when CONFIG_SMP,
and setup.c include it only because it need plat_smp_setup(). So,
reorganize setup.c & smp.h, and then remove <asm/smp.h> in setup.c.
3, Fix cacheinfo.c and percpu.h build error by adding the missing header
files when !CONFIG_SMP.
4, Fix acpi.c build error by adding CONFIG_SMP guards.
5, Move irq_stat definition from smp.c to irq.c and fix its declaration.
6, Select CONFIG_SMP for CONFIG_NUMA, similar as other architectures do.
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-06-05 16:19:53 +08:00
|
|
|
#endif
|
2022-05-31 18:04:11 +08:00
|
|
|
|
|
|
|
paging_init();
|
|
|
|
}
|