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

um_arch.c (11858B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
      4 */
      5
      6#include <linux/delay.h>
      7#include <linux/init.h>
      8#include <linux/mm.h>
      9#include <linux/ctype.h>
     10#include <linux/module.h>
     11#include <linux/panic_notifier.h>
     12#include <linux/seq_file.h>
     13#include <linux/string.h>
     14#include <linux/utsname.h>
     15#include <linux/sched.h>
     16#include <linux/sched/task.h>
     17#include <linux/kmsg_dump.h>
     18#include <linux/suspend.h>
     19
     20#include <asm/processor.h>
     21#include <asm/cpufeature.h>
     22#include <asm/sections.h>
     23#include <asm/setup.h>
     24#include <as-layout.h>
     25#include <arch.h>
     26#include <init.h>
     27#include <kern.h>
     28#include <kern_util.h>
     29#include <mem_user.h>
     30#include <os.h>
     31
     32#include "um_arch.h"
     33
     34#define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
     35#define DEFAULT_COMMAND_LINE_CONSOLE "console=tty"
     36
     37/* Changed in add_arg and setup_arch, which run before SMP is started */
     38static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
     39
     40static void __init add_arg(char *arg)
     41{
     42	if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
     43		os_warn("add_arg: Too many command line arguments!\n");
     44		exit(1);
     45	}
     46	if (strlen(command_line) > 0)
     47		strcat(command_line, " ");
     48	strcat(command_line, arg);
     49}
     50
     51/*
     52 * These fields are initialized at boot time and not changed.
     53 * XXX This structure is used only in the non-SMP case.  Maybe this
     54 * should be moved to smp.c.
     55 */
     56struct cpuinfo_um boot_cpu_data = {
     57	.loops_per_jiffy	= 0,
     58	.ipi_pipe		= { -1, -1 },
     59	.cache_alignment	= L1_CACHE_BYTES,
     60	.x86_capability		= { 0 }
     61};
     62
     63EXPORT_SYMBOL(boot_cpu_data);
     64
     65union thread_union cpu0_irqstack
     66	__section(".data..init_irqstack") =
     67		{ .thread_info = INIT_THREAD_INFO(init_task) };
     68
     69/* Changed in setup_arch, which is called in early boot */
     70static char host_info[(__NEW_UTS_LEN + 1) * 5];
     71
     72static int show_cpuinfo(struct seq_file *m, void *v)
     73{
     74	int i = 0;
     75
     76	seq_printf(m, "processor\t: %d\n", i);
     77	seq_printf(m, "vendor_id\t: User Mode Linux\n");
     78	seq_printf(m, "model name\t: UML\n");
     79	seq_printf(m, "mode\t\t: skas\n");
     80	seq_printf(m, "host\t\t: %s\n", host_info);
     81	seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no");
     82	seq_printf(m, "flags\t\t:");
     83	for (i = 0; i < 32*NCAPINTS; i++)
     84		if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL))
     85			seq_printf(m, " %s", x86_cap_flags[i]);
     86	seq_printf(m, "\n");
     87	seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment);
     88	seq_printf(m, "bogomips\t: %lu.%02lu\n",
     89		   loops_per_jiffy/(500000/HZ),
     90		   (loops_per_jiffy/(5000/HZ)) % 100);
     91
     92
     93	return 0;
     94}
     95
     96static void *c_start(struct seq_file *m, loff_t *pos)
     97{
     98	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
     99}
    100
    101static void *c_next(struct seq_file *m, void *v, loff_t *pos)
    102{
    103	++*pos;
    104	return c_start(m, pos);
    105}
    106
    107static void c_stop(struct seq_file *m, void *v)
    108{
    109}
    110
    111const struct seq_operations cpuinfo_op = {
    112	.start	= c_start,
    113	.next	= c_next,
    114	.stop	= c_stop,
    115	.show	= show_cpuinfo,
    116};
    117
    118/* Set in linux_main */
    119unsigned long uml_physmem;
    120EXPORT_SYMBOL(uml_physmem);
    121
    122unsigned long uml_reserved; /* Also modified in mem_init */
    123unsigned long start_vm;
    124unsigned long end_vm;
    125
    126/* Set in uml_ncpus_setup */
    127int ncpus = 1;
    128
    129/* Set in early boot */
    130static int have_root __initdata;
    131static int have_console __initdata;
    132
    133/* Set in uml_mem_setup and modified in linux_main */
    134long long physmem_size = 32 * 1024 * 1024;
    135EXPORT_SYMBOL(physmem_size);
    136
    137static const char *usage_string =
    138"User Mode Linux v%s\n"
    139"	available at http://user-mode-linux.sourceforge.net/\n\n";
    140
    141static int __init uml_version_setup(char *line, int *add)
    142{
    143	/* Explicitly use printf() to show version in stdout */
    144	printf("%s\n", init_utsname()->release);
    145	exit(0);
    146
    147	return 0;
    148}
    149
    150__uml_setup("--version", uml_version_setup,
    151"--version\n"
    152"    Prints the version number of the kernel.\n\n"
    153);
    154
    155static int __init uml_root_setup(char *line, int *add)
    156{
    157	have_root = 1;
    158	return 0;
    159}
    160
    161__uml_setup("root=", uml_root_setup,
    162"root=<file containing the root fs>\n"
    163"    This is actually used by the generic kernel in exactly the same\n"
    164"    way as in any other kernel. If you configure a number of block\n"
    165"    devices and want to boot off something other than ubd0, you \n"
    166"    would use something like:\n"
    167"        root=/dev/ubd5\n\n"
    168);
    169
    170static int __init no_skas_debug_setup(char *line, int *add)
    171{
    172	os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
    173	os_warn("'gdb linux'\n");
    174
    175	return 0;
    176}
    177
    178__uml_setup("debug", no_skas_debug_setup,
    179"debug\n"
    180"    this flag is not needed to run gdb on UML in skas mode\n\n"
    181);
    182
    183static int __init uml_console_setup(char *line, int *add)
    184{
    185	have_console = 1;
    186	return 0;
    187}
    188
    189__uml_setup("console=", uml_console_setup,
    190"console=<preferred console>\n"
    191"    Specify the preferred console output driver\n\n"
    192);
    193
    194static int __init Usage(char *line, int *add)
    195{
    196	const char **p;
    197
    198	printf(usage_string, init_utsname()->release);
    199	p = &__uml_help_start;
    200	/* Explicitly use printf() to show help in stdout */
    201	while (p < &__uml_help_end) {
    202		printf("%s", *p);
    203		p++;
    204	}
    205	exit(0);
    206	return 0;
    207}
    208
    209__uml_setup("--help", Usage,
    210"--help\n"
    211"    Prints this message.\n\n"
    212);
    213
    214static void __init uml_checksetup(char *line, int *add)
    215{
    216	struct uml_param *p;
    217
    218	p = &__uml_setup_start;
    219	while (p < &__uml_setup_end) {
    220		size_t n;
    221
    222		n = strlen(p->str);
    223		if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
    224			return;
    225		p++;
    226	}
    227}
    228
    229static void __init uml_postsetup(void)
    230{
    231	initcall_t *p;
    232
    233	p = &__uml_postsetup_start;
    234	while (p < &__uml_postsetup_end) {
    235		(*p)();
    236		p++;
    237	}
    238	return;
    239}
    240
    241static int panic_exit(struct notifier_block *self, unsigned long unused1,
    242		      void *unused2)
    243{
    244	kmsg_dump(KMSG_DUMP_PANIC);
    245	bust_spinlocks(1);
    246	bust_spinlocks(0);
    247	uml_exitcode = 1;
    248	os_dump_core();
    249	return 0;
    250}
    251
    252static struct notifier_block panic_exit_notifier = {
    253	.notifier_call 		= panic_exit,
    254	.next 			= NULL,
    255	.priority 		= 0
    256};
    257
    258void uml_finishsetup(void)
    259{
    260	atomic_notifier_chain_register(&panic_notifier_list,
    261				       &panic_exit_notifier);
    262
    263	uml_postsetup();
    264
    265	new_thread_handler();
    266}
    267
    268/* Set during early boot */
    269unsigned long stub_start;
    270unsigned long task_size;
    271EXPORT_SYMBOL(task_size);
    272
    273unsigned long host_task_size;
    274
    275unsigned long brk_start;
    276unsigned long end_iomem;
    277EXPORT_SYMBOL(end_iomem);
    278
    279#define MIN_VMALLOC (32 * 1024 * 1024)
    280
    281static void parse_host_cpu_flags(char *line)
    282{
    283	int i;
    284	for (i = 0; i < 32*NCAPINTS; i++) {
    285		if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i]))
    286			set_cpu_cap(&boot_cpu_data, i);
    287	}
    288}
    289static void parse_cache_line(char *line)
    290{
    291	long res;
    292	char *to_parse = strstr(line, ":");
    293	if (to_parse) {
    294		to_parse++;
    295		while (*to_parse != 0 && isspace(*to_parse)) {
    296			to_parse++;
    297		}
    298		if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res))
    299			boot_cpu_data.cache_alignment = res;
    300		else
    301			boot_cpu_data.cache_alignment = L1_CACHE_BYTES;
    302	}
    303}
    304
    305int __init linux_main(int argc, char **argv)
    306{
    307	unsigned long avail, diff;
    308	unsigned long virtmem_size, max_physmem;
    309	unsigned long stack;
    310	unsigned int i;
    311	int add;
    312
    313	for (i = 1; i < argc; i++) {
    314		if ((i == 1) && (argv[i][0] == ' '))
    315			continue;
    316		add = 1;
    317		uml_checksetup(argv[i], &add);
    318		if (add)
    319			add_arg(argv[i]);
    320	}
    321	if (have_root == 0)
    322		add_arg(DEFAULT_COMMAND_LINE_ROOT);
    323
    324	if (have_console == 0)
    325		add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
    326
    327	host_task_size = os_get_top_address();
    328	/* reserve two pages for the stubs */
    329	host_task_size -= 2 * PAGE_SIZE;
    330	stub_start = host_task_size;
    331
    332	/*
    333	 * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
    334	 * out
    335	 */
    336	task_size = host_task_size & PGDIR_MASK;
    337
    338	/* OS sanity checks that need to happen before the kernel runs */
    339	os_early_checks();
    340
    341	get_host_cpu_features(parse_host_cpu_flags, parse_cache_line);
    342
    343	brk_start = (unsigned long) sbrk(0);
    344
    345	/*
    346	 * Increase physical memory size for exec-shield users
    347	 * so they actually get what they asked for. This should
    348	 * add zero for non-exec shield users
    349	 */
    350
    351	diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
    352	if (diff > 1024 * 1024) {
    353		os_info("Adding %ld bytes to physical memory to account for "
    354			"exec-shield gap\n", diff);
    355		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
    356	}
    357
    358	uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
    359
    360	/* Reserve up to 4M after the current brk */
    361	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
    362
    363	setup_machinename(init_utsname()->machine);
    364
    365	highmem = 0;
    366	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
    367	max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
    368
    369	/*
    370	 * Zones have to begin on a 1 << MAX_ORDER page boundary,
    371	 * so this makes sure that's true for highmem
    372	 */
    373	max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
    374	if (physmem_size + iomem_size > max_physmem) {
    375		highmem = physmem_size + iomem_size - max_physmem;
    376		physmem_size -= highmem;
    377	}
    378
    379	high_physmem = uml_physmem + physmem_size;
    380	end_iomem = high_physmem + iomem_size;
    381	high_memory = (void *) end_iomem;
    382
    383	start_vm = VMALLOC_START;
    384
    385	virtmem_size = physmem_size;
    386	stack = (unsigned long) argv;
    387	stack &= ~(1024 * 1024 - 1);
    388	avail = stack - start_vm;
    389	if (physmem_size > avail)
    390		virtmem_size = avail;
    391	end_vm = start_vm + virtmem_size;
    392
    393	if (virtmem_size < physmem_size)
    394		os_info("Kernel virtual memory size shrunk to %lu bytes\n",
    395			virtmem_size);
    396
    397	os_flush_stdout();
    398
    399	return start_uml();
    400}
    401
    402int __init __weak read_initrd(void)
    403{
    404	return 0;
    405}
    406
    407void __init setup_arch(char **cmdline_p)
    408{
    409	stack_protections((unsigned long) &init_thread_info);
    410	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
    411	mem_total_pages(physmem_size, iomem_size, highmem);
    412	uml_dtb_init();
    413	read_initrd();
    414
    415	paging_init();
    416	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
    417	*cmdline_p = command_line;
    418	setup_hostinfo(host_info, sizeof host_info);
    419}
    420
    421void __init check_bugs(void)
    422{
    423	arch_check_bugs();
    424	os_check_bugs();
    425}
    426
    427void apply_ibt_endbr(s32 *start, s32 *end)
    428{
    429}
    430
    431void apply_retpolines(s32 *start, s32 *end)
    432{
    433}
    434
    435void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
    436{
    437}
    438
    439void *text_poke(void *addr, const void *opcode, size_t len)
    440{
    441	/*
    442	 * In UML, the only reference to this function is in
    443	 * apply_relocate_add(), which shouldn't ever actually call this
    444	 * because UML doesn't have live patching.
    445	 */
    446	WARN_ON(1);
    447
    448	return memcpy(addr, opcode, len);
    449}
    450
    451void text_poke_sync(void)
    452{
    453}
    454
    455void uml_pm_wake(void)
    456{
    457	pm_system_wakeup();
    458}
    459
    460#ifdef CONFIG_PM_SLEEP
    461static int um_suspend_valid(suspend_state_t state)
    462{
    463	return state == PM_SUSPEND_MEM;
    464}
    465
    466static int um_suspend_prepare(void)
    467{
    468	um_irqs_suspend();
    469	return 0;
    470}
    471
    472static int um_suspend_enter(suspend_state_t state)
    473{
    474	if (WARN_ON(state != PM_SUSPEND_MEM))
    475		return -EINVAL;
    476
    477	/*
    478	 * This is identical to the idle sleep, but we've just
    479	 * (during suspend) turned off all interrupt sources
    480	 * except for the ones we want, so now we can only wake
    481	 * up on something we actually want to wake up on. All
    482	 * timing has also been suspended.
    483	 */
    484	um_idle_sleep();
    485	return 0;
    486}
    487
    488static void um_suspend_finish(void)
    489{
    490	um_irqs_resume();
    491}
    492
    493const struct platform_suspend_ops um_suspend_ops = {
    494	.valid = um_suspend_valid,
    495	.prepare = um_suspend_prepare,
    496	.enter = um_suspend_enter,
    497	.finish = um_suspend_finish,
    498};
    499
    500static int init_pm_wake_signal(void)
    501{
    502	/*
    503	 * In external time-travel mode we can't use signals to wake up
    504	 * since that would mess with the scheduling. We'll have to do
    505	 * some additional work to support wakeup on virtio devices or
    506	 * similar, perhaps implementing a fake RTC controller that can
    507	 * trigger wakeup (and request the appropriate scheduling from
    508	 * the external scheduler when going to suspend.)
    509	 */
    510	if (time_travel_mode != TT_MODE_EXTERNAL)
    511		register_pm_wake_signal();
    512
    513	suspend_set_ops(&um_suspend_ops);
    514
    515	return 0;
    516}
    517
    518late_initcall(init_pm_wake_signal);
    519#endif