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

cpu_ops_spinwait.c (2089B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
      4 */
      5
      6#include <linux/errno.h>
      7#include <linux/of.h>
      8#include <linux/string.h>
      9#include <linux/sched/task_stack.h>
     10#include <asm/cpu_ops.h>
     11#include <asm/sbi.h>
     12#include <asm/smp.h>
     13
     14const struct cpu_operations cpu_ops_spinwait;
     15void *__cpu_spinwait_stack_pointer[NR_CPUS] __section(".data");
     16void *__cpu_spinwait_task_pointer[NR_CPUS] __section(".data");
     17
     18static void cpu_update_secondary_bootdata(unsigned int cpuid,
     19				   struct task_struct *tidle)
     20{
     21	int hartid = cpuid_to_hartid_map(cpuid);
     22
     23	/*
     24	 * The hartid must be less than NR_CPUS to avoid out-of-bound access
     25	 * errors for __cpu_spinwait_stack/task_pointer. That is not always possible
     26	 * for platforms with discontiguous hartid numbering scheme. That's why
     27	 * spinwait booting is not the recommended approach for any platforms
     28	 * booting Linux in S-mode and can be disabled in the future.
     29	 */
     30	if (hartid == INVALID_HARTID || hartid >= NR_CPUS)
     31		return;
     32
     33	/* Make sure tidle is updated */
     34	smp_mb();
     35	WRITE_ONCE(__cpu_spinwait_stack_pointer[hartid],
     36		   task_stack_page(tidle) + THREAD_SIZE);
     37	WRITE_ONCE(__cpu_spinwait_task_pointer[hartid], tidle);
     38}
     39
     40static int spinwait_cpu_prepare(unsigned int cpuid)
     41{
     42	if (!cpu_ops_spinwait.cpu_start) {
     43		pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
     44		return -ENODEV;
     45	}
     46	return 0;
     47}
     48
     49static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle)
     50{
     51	/*
     52	 * In this protocol, all cpus boot on their own accord.  _start
     53	 * selects the first cpu to boot the kernel and causes the remainder
     54	 * of the cpus to spin in a loop waiting for their stack pointer to be
     55	 * setup by that main cpu.  Writing to bootdata
     56	 * (i.e __cpu_spinwait_stack_pointer) signals to the spinning cpus that they
     57	 * can continue the boot process.
     58	 */
     59	cpu_update_secondary_bootdata(cpuid, tidle);
     60
     61	return 0;
     62}
     63
     64const struct cpu_operations cpu_ops_spinwait = {
     65	.name		= "spinwait",
     66	.cpu_prepare	= spinwait_cpu_prepare,
     67	.cpu_start	= spinwait_cpu_start,
     68};