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

reset.c (4073B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *
      4 * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
      5 * Author: Fuxin Zhang, zhangfx@lemote.com
      6 * Copyright (C) 2009 Lemote, Inc.
      7 * Author: Zhangjin Wu, wuzhangjin@gmail.com
      8 */
      9#include <linux/cpu.h>
     10#include <linux/delay.h>
     11#include <linux/init.h>
     12#include <linux/kexec.h>
     13#include <linux/pm.h>
     14#include <linux/slab.h>
     15
     16#include <asm/bootinfo.h>
     17#include <asm/idle.h>
     18#include <asm/reboot.h>
     19
     20#include <loongson.h>
     21#include <boot_param.h>
     22
     23static void loongson_restart(char *command)
     24{
     25
     26	void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
     27
     28	fw_restart();
     29	while (1) {
     30		if (cpu_wait)
     31			cpu_wait();
     32	}
     33}
     34
     35static void loongson_poweroff(void)
     36{
     37	void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
     38
     39	fw_poweroff();
     40	while (1) {
     41		if (cpu_wait)
     42			cpu_wait();
     43	}
     44}
     45
     46static void loongson_halt(void)
     47{
     48	pr_notice("\n\n** You can safely turn off the power now **\n\n");
     49	while (1) {
     50		if (cpu_wait)
     51			cpu_wait();
     52	}
     53}
     54
     55#ifdef CONFIG_KEXEC
     56
     57/* 0X80000000~0X80200000 is safe */
     58#define MAX_ARGS	64
     59#define KEXEC_CTRL_CODE	0xFFFFFFFF80100000UL
     60#define KEXEC_ARGV_ADDR	0xFFFFFFFF80108000UL
     61#define KEXEC_ARGV_SIZE	COMMAND_LINE_SIZE
     62#define KEXEC_ENVP_SIZE	4800
     63
     64static int kexec_argc;
     65static int kdump_argc;
     66static void *kexec_argv;
     67static void *kdump_argv;
     68static void *kexec_envp;
     69
     70static int loongson_kexec_prepare(struct kimage *image)
     71{
     72	int i, argc = 0;
     73	unsigned int *argv;
     74	char *str, *ptr, *bootloader = "kexec";
     75
     76	/* argv at offset 0, argv[] at offset KEXEC_ARGV_SIZE/2 */
     77	if (image->type == KEXEC_TYPE_DEFAULT)
     78		argv = (unsigned int *)kexec_argv;
     79	else
     80		argv = (unsigned int *)kdump_argv;
     81
     82	argv[argc++] = (unsigned int)(KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2);
     83
     84	for (i = 0; i < image->nr_segments; i++) {
     85		if (!strncmp(bootloader, (char *)image->segment[i].buf,
     86				strlen(bootloader))) {
     87			/*
     88			 * convert command line string to array
     89			 * of parameters (as bootloader does).
     90			 */
     91			int offt;
     92			str = (char *)argv + KEXEC_ARGV_SIZE/2;
     93			memcpy(str, image->segment[i].buf, KEXEC_ARGV_SIZE/2);
     94			ptr = strchr(str, ' ');
     95
     96			while (ptr && (argc < MAX_ARGS)) {
     97				*ptr = '\0';
     98				if (ptr[1] != ' ') {
     99					offt = (int)(ptr - str + 1);
    100					argv[argc] = KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2 + offt;
    101					argc++;
    102				}
    103				ptr = strchr(ptr + 1, ' ');
    104			}
    105			break;
    106		}
    107	}
    108
    109	if (image->type == KEXEC_TYPE_DEFAULT)
    110		kexec_argc = argc;
    111	else
    112		kdump_argc = argc;
    113
    114	/* kexec/kdump need a safe page to save reboot_code_buffer */
    115	image->control_code_page = virt_to_page((void *)KEXEC_CTRL_CODE);
    116
    117	return 0;
    118}
    119
    120static void loongson_kexec_shutdown(void)
    121{
    122#ifdef CONFIG_SMP
    123	int cpu;
    124
    125	/* All CPUs go to reboot_code_buffer */
    126	for_each_possible_cpu(cpu)
    127		if (!cpu_online(cpu))
    128			cpu_device_up(get_cpu_device(cpu));
    129
    130	secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
    131#endif
    132	kexec_args[0] = kexec_argc;
    133	kexec_args[1] = fw_arg1;
    134	kexec_args[2] = fw_arg2;
    135	memcpy((void *)fw_arg1, kexec_argv, KEXEC_ARGV_SIZE);
    136	memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
    137}
    138
    139static void loongson_crash_shutdown(struct pt_regs *regs)
    140{
    141	default_machine_crash_shutdown(regs);
    142	kexec_args[0] = kdump_argc;
    143	kexec_args[1] = fw_arg1;
    144	kexec_args[2] = fw_arg2;
    145#ifdef CONFIG_SMP
    146	secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
    147#endif
    148	memcpy((void *)fw_arg1, kdump_argv, KEXEC_ARGV_SIZE);
    149	memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
    150}
    151
    152#endif
    153
    154static int __init mips_reboot_setup(void)
    155{
    156	_machine_restart = loongson_restart;
    157	_machine_halt = loongson_halt;
    158	pm_power_off = loongson_poweroff;
    159
    160#ifdef CONFIG_KEXEC
    161	kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
    162	kdump_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
    163	kexec_envp = kmalloc(KEXEC_ENVP_SIZE, GFP_KERNEL);
    164	fw_arg1 = KEXEC_ARGV_ADDR;
    165	memcpy(kexec_envp, (void *)fw_arg2, KEXEC_ENVP_SIZE);
    166
    167	_machine_kexec_prepare = loongson_kexec_prepare;
    168	_machine_kexec_shutdown = loongson_kexec_shutdown;
    169	_machine_crash_shutdown = loongson_crash_shutdown;
    170#endif
    171
    172	return 0;
    173}
    174
    175arch_initcall(mips_reboot_setup);