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

pj4-cp0.c (2758B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/arch/arm/kernel/pj4-cp0.c
      4 *
      5 * PJ4 iWMMXt coprocessor context switching and handling
      6 *
      7 * Copyright (c) 2010 Marvell International Inc.
      8 */
      9
     10#include <linux/types.h>
     11#include <linux/kernel.h>
     12#include <linux/signal.h>
     13#include <linux/sched.h>
     14#include <linux/init.h>
     15#include <linux/io.h>
     16#include <asm/thread_notify.h>
     17#include <asm/cputype.h>
     18
     19static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
     20{
     21	struct thread_info *thread = t;
     22
     23	switch (cmd) {
     24	case THREAD_NOTIFY_FLUSH:
     25		/*
     26		 * flush_thread() zeroes thread->fpstate, so no need
     27		 * to do anything here.
     28		 *
     29		 * FALLTHROUGH: Ensure we don't try to overwrite our newly
     30		 * initialised state information on the first fault.
     31		 */
     32
     33	case THREAD_NOTIFY_EXIT:
     34		iwmmxt_task_release(thread);
     35		break;
     36
     37	case THREAD_NOTIFY_SWITCH:
     38		iwmmxt_task_switch(thread);
     39		break;
     40	}
     41
     42	return NOTIFY_DONE;
     43}
     44
     45static struct notifier_block __maybe_unused iwmmxt_notifier_block = {
     46	.notifier_call	= iwmmxt_do,
     47};
     48
     49
     50static u32 __init pj4_cp_access_read(void)
     51{
     52	u32 value;
     53
     54	__asm__ __volatile__ (
     55		"mrc	p15, 0, %0, c1, c0, 2\n\t"
     56		: "=r" (value));
     57	return value;
     58}
     59
     60static void __init pj4_cp_access_write(u32 value)
     61{
     62	u32 temp;
     63
     64	__asm__ __volatile__ (
     65		"mcr	p15, 0, %1, c1, c0, 2\n\t"
     66#ifdef CONFIG_THUMB2_KERNEL
     67		"isb\n\t"
     68#else
     69		"mrc	p15, 0, %0, c1, c0, 2\n\t"
     70		"mov	%0, %0\n\t"
     71		"sub	pc, pc, #4\n\t"
     72#endif
     73		: "=r" (temp) : "r" (value));
     74}
     75
     76static int __init pj4_get_iwmmxt_version(void)
     77{
     78	u32 cp_access, wcid;
     79
     80	cp_access = pj4_cp_access_read();
     81	pj4_cp_access_write(cp_access | 0xf);
     82
     83	/* check if coprocessor 0 and 1 are available */
     84	if ((pj4_cp_access_read() & 0xf) != 0xf) {
     85		pj4_cp_access_write(cp_access);
     86		return -ENODEV;
     87	}
     88
     89	/* read iWMMXt coprocessor id register p1, c0 */
     90	__asm__ __volatile__ ("mrc    p1, 0, %0, c0, c0, 0\n" : "=r" (wcid));
     91
     92	pj4_cp_access_write(cp_access);
     93
     94	/* iWMMXt v1 */
     95	if ((wcid & 0xffffff00) == 0x56051000)
     96		return 1;
     97	/* iWMMXt v2 */
     98	if ((wcid & 0xffffff00) == 0x56052000)
     99		return 2;
    100
    101	return -EINVAL;
    102}
    103
    104/*
    105 * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
    106 * switch code handle iWMMXt context switching.
    107 */
    108static int __init pj4_cp0_init(void)
    109{
    110	u32 __maybe_unused cp_access;
    111	int vers;
    112
    113	if (!cpu_is_pj4())
    114		return 0;
    115
    116	vers = pj4_get_iwmmxt_version();
    117	if (vers < 0)
    118		return 0;
    119
    120#ifndef CONFIG_IWMMXT
    121	pr_info("PJ4 iWMMXt coprocessor detected, but kernel support is missing.\n");
    122#else
    123	cp_access = pj4_cp_access_read() & ~0xf;
    124	pj4_cp_access_write(cp_access);
    125
    126	pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
    127	elf_hwcap |= HWCAP_IWMMXT;
    128	thread_register_notifier(&iwmmxt_notifier_block);
    129#endif
    130
    131	return 0;
    132}
    133
    134late_initcall(pj4_cp0_init);