cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

setup.c (9132B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
      4 *
      5 * Derived from MIPS:
      6 * Copyright (C) 1995 Linus Torvalds
      7 * Copyright (C) 1995 Waldorf Electronics
      8 * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03  Ralf Baechle
      9 * Copyright (C) 1996 Stoned Elipot
     10 * Copyright (C) 1999 Silicon Graphics, Inc.
     11 * Copyright (C) 2000, 2001, 2002, 2007	 Maciej W. Rozycki
     12 */
     13#include <linux/init.h>
     14#include <linux/acpi.h>
     15#include <linux/dmi.h>
     16#include <linux/efi.h>
     17#include <linux/export.h>
     18#include <linux/screen_info.h>
     19#include <linux/memblock.h>
     20#include <linux/initrd.h>
     21#include <linux/ioport.h>
     22#include <linux/root_dev.h>
     23#include <linux/console.h>
     24#include <linux/pfn.h>
     25#include <linux/platform_device.h>
     26#include <linux/sizes.h>
     27#include <linux/device.h>
     28#include <linux/dma-map-ops.h>
     29#include <linux/swiotlb.h>
     30
     31#include <asm/addrspace.h>
     32#include <asm/bootinfo.h>
     33#include <asm/cache.h>
     34#include <asm/cpu.h>
     35#include <asm/dma.h>
     36#include <asm/efi.h>
     37#include <asm/loongson.h>
     38#include <asm/numa.h>
     39#include <asm/pgalloc.h>
     40#include <asm/sections.h>
     41#include <asm/setup.h>
     42#include <asm/time.h>
     43
     44#define SMBIOS_BIOSSIZE_OFFSET		0x09
     45#define SMBIOS_BIOSEXTERN_OFFSET	0x13
     46#define SMBIOS_FREQLOW_OFFSET		0x16
     47#define SMBIOS_FREQHIGH_OFFSET		0x17
     48#define SMBIOS_FREQLOW_MASK		0xFF
     49#define SMBIOS_CORE_PACKAGE_OFFSET	0x23
     50#define LOONGSON_EFI_ENABLE		(1 << 3)
     51
     52#ifdef CONFIG_VT
     53struct screen_info screen_info;
     54#endif
     55
     56unsigned long fw_arg0, fw_arg1;
     57DEFINE_PER_CPU(unsigned long, kernelsp);
     58struct cpuinfo_loongarch cpu_data[NR_CPUS] __read_mostly;
     59
     60EXPORT_SYMBOL(cpu_data);
     61
     62struct loongson_board_info b_info;
     63static const char dmi_empty_string[] = "        ";
     64
     65/*
     66 * Setup information
     67 *
     68 * These are initialized so they are in the .data section
     69 */
     70
     71static int num_standard_resources;
     72static struct resource *standard_resources;
     73
     74static struct resource code_resource = { .name = "Kernel code", };
     75static struct resource data_resource = { .name = "Kernel data", };
     76static struct resource bss_resource  = { .name = "Kernel bss", };
     77
     78const char *get_system_type(void)
     79{
     80	return "generic-loongson-machine";
     81}
     82
     83static const char *dmi_string_parse(const struct dmi_header *dm, u8 s)
     84{
     85	const u8 *bp = ((u8 *) dm) + dm->length;
     86
     87	if (s) {
     88		s--;
     89		while (s > 0 && *bp) {
     90			bp += strlen(bp) + 1;
     91			s--;
     92		}
     93
     94		if (*bp != 0) {
     95			size_t len = strlen(bp)+1;
     96			size_t cmp_len = len > 8 ? 8 : len;
     97
     98			if (!memcmp(bp, dmi_empty_string, cmp_len))
     99				return dmi_empty_string;
    100
    101			return bp;
    102		}
    103	}
    104
    105	return "";
    106}
    107
    108static void __init parse_cpu_table(const struct dmi_header *dm)
    109{
    110	long freq_temp = 0;
    111	char *dmi_data = (char *)dm;
    112
    113	freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) +
    114			((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK));
    115	cpu_clock_freq = freq_temp * 1000000;
    116
    117	loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
    118	loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET);
    119
    120	pr_info("CpuClock = %llu\n", cpu_clock_freq);
    121}
    122
    123static void __init parse_bios_table(const struct dmi_header *dm)
    124{
    125	int bios_extern;
    126	char *dmi_data = (char *)dm;
    127
    128	bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
    129	b_info.bios_size = *(dmi_data + SMBIOS_BIOSSIZE_OFFSET);
    130
    131	if (bios_extern & LOONGSON_EFI_ENABLE)
    132		set_bit(EFI_BOOT, &efi.flags);
    133	else
    134		clear_bit(EFI_BOOT, &efi.flags);
    135}
    136
    137static void __init find_tokens(const struct dmi_header *dm, void *dummy)
    138{
    139	switch (dm->type) {
    140	case 0x0: /* Extern BIOS */
    141		parse_bios_table(dm);
    142		break;
    143	case 0x4: /* Calling interface */
    144		parse_cpu_table(dm);
    145		break;
    146	}
    147}
    148static void __init smbios_parse(void)
    149{
    150	b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
    151	b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION);
    152	b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE);
    153	b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR);
    154	b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME);
    155	dmi_walk(find_tokens, NULL);
    156}
    157
    158static int usermem __initdata;
    159
    160static int __init early_parse_mem(char *p)
    161{
    162	phys_addr_t start, size;
    163
    164	if (!p) {
    165		pr_err("mem parameter is empty, do nothing\n");
    166		return -EINVAL;
    167	}
    168
    169	/*
    170	 * If a user specifies memory size, we
    171	 * blow away any automatically generated
    172	 * size.
    173	 */
    174	if (usermem == 0) {
    175		usermem = 1;
    176		memblock_remove(memblock_start_of_DRAM(),
    177			memblock_end_of_DRAM() - memblock_start_of_DRAM());
    178	}
    179	start = 0;
    180	size = memparse(p, &p);
    181	if (*p == '@')
    182		start = memparse(p + 1, &p);
    183	else {
    184		pr_err("Invalid format!\n");
    185		return -EINVAL;
    186	}
    187
    188	if (!IS_ENABLED(CONFIG_NUMA))
    189		memblock_add(start, size);
    190	else
    191		memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE);
    192
    193	return 0;
    194}
    195early_param("mem", early_parse_mem);
    196
    197void __init platform_init(void)
    198{
    199	efi_init();
    200#ifdef CONFIG_ACPI_TABLE_UPGRADE
    201	acpi_table_upgrade();
    202#endif
    203#ifdef CONFIG_ACPI
    204	acpi_gbl_use_default_register_widths = false;
    205	acpi_boot_table_init();
    206	acpi_boot_init();
    207#endif
    208
    209#ifdef CONFIG_NUMA
    210	init_numa_memory();
    211#endif
    212	dmi_setup();
    213	smbios_parse();
    214	pr_info("The BIOS Version: %s\n", b_info.bios_version);
    215
    216	efi_runtime_init();
    217}
    218
    219static void __init check_kernel_sections_mem(void)
    220{
    221	phys_addr_t start = __pa_symbol(&_text);
    222	phys_addr_t size = __pa_symbol(&_end) - start;
    223
    224	if (!memblock_is_region_memory(start, size)) {
    225		pr_info("Kernel sections are not in the memory maps\n");
    226		memblock_add(start, size);
    227	}
    228}
    229
    230/*
    231 * arch_mem_init - initialize memory management subsystem
    232 */
    233static void __init arch_mem_init(char **cmdline_p)
    234{
    235	if (usermem)
    236		pr_info("User-defined physical RAM map overwrite\n");
    237
    238	check_kernel_sections_mem();
    239
    240	/*
    241	 * In order to reduce the possibility of kernel panic when failed to
    242	 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
    243	 * low memory as small as possible before plat_swiotlb_setup(), so
    244	 * make sparse_init() using top-down allocation.
    245	 */
    246	memblock_set_bottom_up(false);
    247	sparse_init();
    248	memblock_set_bottom_up(true);
    249
    250	plat_swiotlb_setup();
    251
    252	dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
    253
    254	memblock_dump_all();
    255
    256	early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
    257}
    258
    259static void __init resource_init(void)
    260{
    261	long i = 0;
    262	size_t res_size;
    263	struct resource *res;
    264	struct memblock_region *region;
    265
    266	code_resource.start = __pa_symbol(&_text);
    267	code_resource.end = __pa_symbol(&_etext) - 1;
    268	data_resource.start = __pa_symbol(&_etext);
    269	data_resource.end = __pa_symbol(&_edata) - 1;
    270	bss_resource.start = __pa_symbol(&__bss_start);
    271	bss_resource.end = __pa_symbol(&__bss_stop) - 1;
    272
    273	num_standard_resources = memblock.memory.cnt;
    274	res_size = num_standard_resources * sizeof(*standard_resources);
    275	standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES);
    276
    277	for_each_mem_region(region) {
    278		res = &standard_resources[i++];
    279		if (!memblock_is_nomap(region)) {
    280			res->name  = "System RAM";
    281			res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
    282			res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
    283			res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
    284		} else {
    285			res->name  = "Reserved";
    286			res->flags = IORESOURCE_MEM;
    287			res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region));
    288			res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1;
    289		}
    290
    291		request_resource(&iomem_resource, res);
    292
    293		/*
    294		 *  We don't know which RAM region contains kernel data,
    295		 *  so we try it repeatedly and let the resource manager
    296		 *  test it.
    297		 */
    298		request_resource(res, &code_resource);
    299		request_resource(res, &data_resource);
    300		request_resource(res, &bss_resource);
    301	}
    302}
    303
    304static int __init reserve_memblock_reserved_regions(void)
    305{
    306	u64 i, j;
    307
    308	for (i = 0; i < num_standard_resources; ++i) {
    309		struct resource *mem = &standard_resources[i];
    310		phys_addr_t r_start, r_end, mem_size = resource_size(mem);
    311
    312		if (!memblock_is_region_reserved(mem->start, mem_size))
    313			continue;
    314
    315		for_each_reserved_mem_range(j, &r_start, &r_end) {
    316			resource_size_t start, end;
    317
    318			start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start);
    319			end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end);
    320
    321			if (start > mem->end || end < mem->start)
    322				continue;
    323
    324			reserve_region_with_split(mem, start, end, "Reserved");
    325		}
    326	}
    327
    328	return 0;
    329}
    330arch_initcall(reserve_memblock_reserved_regions);
    331
    332#ifdef CONFIG_SMP
    333static void __init prefill_possible_map(void)
    334{
    335	int i, possible;
    336
    337	possible = num_processors + disabled_cpus;
    338	if (possible > nr_cpu_ids)
    339		possible = nr_cpu_ids;
    340
    341	pr_info("SMP: Allowing %d CPUs, %d hotplug CPUs\n",
    342			possible, max((possible - num_processors), 0));
    343
    344	for (i = 0; i < possible; i++)
    345		set_cpu_possible(i, true);
    346	for (; i < NR_CPUS; i++)
    347		set_cpu_possible(i, false);
    348
    349	nr_cpu_ids = possible;
    350}
    351#endif
    352
    353void __init setup_arch(char **cmdline_p)
    354{
    355	cpu_probe();
    356	*cmdline_p = boot_command_line;
    357
    358	init_environ();
    359	memblock_init();
    360	parse_early_param();
    361
    362	platform_init();
    363	pagetable_init();
    364	arch_mem_init(cmdline_p);
    365
    366	resource_init();
    367#ifdef CONFIG_SMP
    368	plat_smp_setup();
    369	prefill_possible_map();
    370#endif
    371
    372	paging_init();
    373}