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

olpc_ofw.c (2897B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/kernel.h>
      3#include <linux/export.h>
      4#include <linux/spinlock_types.h>
      5#include <linux/init.h>
      6#include <linux/pgtable.h>
      7#include <asm/page.h>
      8#include <asm/setup.h>
      9#include <asm/io.h>
     10#include <asm/cpufeature.h>
     11#include <asm/special_insns.h>
     12#include <asm/olpc_ofw.h>
     13
     14/* address of OFW callback interface; will be NULL if OFW isn't found */
     15static int (*olpc_ofw_cif)(int *);
     16
     17/* page dir entry containing OFW's pgdir table; filled in by head_32.S */
     18u32 olpc_ofw_pgd __initdata;
     19
     20static DEFINE_SPINLOCK(ofw_lock);
     21
     22#define MAXARGS 10
     23
     24void __init setup_olpc_ofw_pgd(void)
     25{
     26	pgd_t *base, *ofw_pde;
     27
     28	if (!olpc_ofw_cif)
     29		return;
     30
     31	/* fetch OFW's PDE */
     32	base = early_ioremap(olpc_ofw_pgd, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
     33	if (!base) {
     34		printk(KERN_ERR "failed to remap OFW's pgd - disabling OFW!\n");
     35		olpc_ofw_cif = NULL;
     36		return;
     37	}
     38	ofw_pde = &base[OLPC_OFW_PDE_NR];
     39
     40	/* install OFW's PDE permanently into the kernel's pgtable */
     41	set_pgd(&swapper_pg_dir[OLPC_OFW_PDE_NR], *ofw_pde);
     42	/* implicit optimization barrier here due to uninline function return */
     43
     44	early_iounmap(base, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
     45}
     46
     47int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
     48		void **res)
     49{
     50	int ofw_args[MAXARGS + 3];
     51	unsigned long flags;
     52	int ret, i, *p;
     53
     54	BUG_ON(nr_args + nr_res > MAXARGS);
     55
     56	if (!olpc_ofw_cif)
     57		return -EIO;
     58
     59	ofw_args[0] = (int)name;
     60	ofw_args[1] = nr_args;
     61	ofw_args[2] = nr_res;
     62
     63	p = &ofw_args[3];
     64	for (i = 0; i < nr_args; i++, p++)
     65		*p = (int)args[i];
     66
     67	/* call into ofw */
     68	spin_lock_irqsave(&ofw_lock, flags);
     69	ret = olpc_ofw_cif(ofw_args);
     70	spin_unlock_irqrestore(&ofw_lock, flags);
     71
     72	if (!ret) {
     73		for (i = 0; i < nr_res; i++, p++)
     74			*((int *)res[i]) = *p;
     75	}
     76
     77	return ret;
     78}
     79EXPORT_SYMBOL_GPL(__olpc_ofw);
     80
     81bool olpc_ofw_present(void)
     82{
     83	return olpc_ofw_cif != NULL;
     84}
     85EXPORT_SYMBOL_GPL(olpc_ofw_present);
     86
     87/* OFW cif _should_ be above this address */
     88#define OFW_MIN 0xff000000
     89
     90/* OFW starts on a 1MB boundary */
     91#define OFW_BOUND (1<<20)
     92
     93void __init olpc_ofw_detect(void)
     94{
     95	struct olpc_ofw_header *hdr = &boot_params.olpc_ofw_header;
     96	unsigned long start;
     97
     98	/* ensure OFW booted us by checking for "OFW " string */
     99	if (hdr->ofw_magic != OLPC_OFW_SIG)
    100		return;
    101
    102	olpc_ofw_cif = (int (*)(int *))hdr->cif_handler;
    103
    104	if ((unsigned long)olpc_ofw_cif < OFW_MIN) {
    105		printk(KERN_ERR "OFW detected, but cif has invalid address 0x%lx - disabling.\n",
    106				(unsigned long)olpc_ofw_cif);
    107		olpc_ofw_cif = NULL;
    108		return;
    109	}
    110
    111	/* determine where OFW starts in memory */
    112	start = round_down((unsigned long)olpc_ofw_cif, OFW_BOUND);
    113	printk(KERN_INFO "OFW detected in memory, cif @ 0x%lx (reserving top %ldMB)\n",
    114			(unsigned long)olpc_ofw_cif, (-start) >> 20);
    115	reserve_top_address(-start);
    116}
    117
    118bool __init olpc_ofw_is_installed(void)
    119{
    120	return olpc_ofw_cif != NULL;
    121}