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

sh_bios.c (3877B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  C interface for trapping into the standard LinuxSH BIOS.
      4 *
      5 *  Copyright (C) 2000 Greg Banks, Mitch Davis
      6 *  Copyright (C) 1999, 2000  Niibe Yutaka
      7 *  Copyright (C) 2002  M. R. Brown
      8 *  Copyright (C) 2004 - 2010  Paul Mundt
      9 */
     10#include <linux/module.h>
     11#include <linux/console.h>
     12#include <linux/tty.h>
     13#include <linux/init.h>
     14#include <linux/io.h>
     15#include <linux/delay.h>
     16#include <asm/sh_bios.h>
     17
     18#define BIOS_CALL_CONSOLE_WRITE		0
     19#define BIOS_CALL_ETH_NODE_ADDR		10
     20#define BIOS_CALL_SHUTDOWN		11
     21#define BIOS_CALL_GDB_DETACH		0xff
     22
     23void *gdb_vbr_vector = NULL;
     24
     25static inline long sh_bios_call(long func, long arg0, long arg1, long arg2,
     26				    long arg3)
     27{
     28	register long r0 __asm__("r0") = func;
     29	register long r4 __asm__("r4") = arg0;
     30	register long r5 __asm__("r5") = arg1;
     31	register long r6 __asm__("r6") = arg2;
     32	register long r7 __asm__("r7") = arg3;
     33
     34	if (!gdb_vbr_vector)
     35		return -ENOSYS;
     36
     37	__asm__ __volatile__("trapa	#0x3f":"=z"(r0)
     38			     :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7)
     39			     :"memory");
     40	return r0;
     41}
     42
     43void sh_bios_console_write(const char *buf, unsigned int len)
     44{
     45	sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
     46}
     47
     48void sh_bios_gdb_detach(void)
     49{
     50	sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
     51}
     52EXPORT_SYMBOL_GPL(sh_bios_gdb_detach);
     53
     54void sh_bios_get_node_addr(unsigned char *node_addr)
     55{
     56	sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0);
     57}
     58EXPORT_SYMBOL_GPL(sh_bios_get_node_addr);
     59
     60void sh_bios_shutdown(unsigned int how)
     61{
     62	sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
     63}
     64
     65/*
     66 * Read the old value of the VBR register to initialise the vector
     67 * through which debug and BIOS traps are delegated by the Linux trap
     68 * handler.
     69 */
     70void sh_bios_vbr_init(void)
     71{
     72	unsigned long vbr;
     73
     74	if (unlikely(gdb_vbr_vector))
     75		return;
     76
     77	__asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr));
     78
     79	if (vbr) {
     80		gdb_vbr_vector = (void *)(vbr + 0x100);
     81		printk(KERN_NOTICE "Setting GDB trap vector to %p\n",
     82		       gdb_vbr_vector);
     83	} else
     84		printk(KERN_NOTICE "SH-BIOS not detected\n");
     85}
     86
     87/**
     88 * sh_bios_vbr_reload - Re-load the system VBR from the BIOS vector.
     89 *
     90 * This can be used by save/restore code to reinitialize the system VBR
     91 * from the fixed BIOS VBR. A no-op if no BIOS VBR is known.
     92 */
     93void sh_bios_vbr_reload(void)
     94{
     95	if (gdb_vbr_vector)
     96		__asm__ __volatile__ (
     97			"ldc %0, vbr"
     98			:
     99			: "r" (((unsigned long) gdb_vbr_vector) - 0x100)
    100			: "memory"
    101		);
    102}
    103
    104#ifdef CONFIG_EARLY_PRINTK
    105/*
    106 *	Print a string through the BIOS
    107 */
    108static void sh_console_write(struct console *co, const char *s,
    109				 unsigned count)
    110{
    111	sh_bios_console_write(s, count);
    112}
    113
    114/*
    115 *	Setup initial baud/bits/parity. We do two things here:
    116 *	- construct a cflag setting for the first rs_open()
    117 *	- initialize the serial port
    118 *	Return non-zero if we didn't find a serial port.
    119 */
    120static int __init sh_console_setup(struct console *co, char *options)
    121{
    122	int	cflag = CREAD | HUPCL | CLOCAL;
    123
    124	/*
    125	 *	Now construct a cflag setting.
    126	 *	TODO: this is a totally bogus cflag, as we have
    127	 *	no idea what serial settings the BIOS is using, or
    128	 *	even if its using the serial port at all.
    129	 */
    130	cflag |= B115200 | CS8 | /*no parity*/0;
    131
    132	co->cflag = cflag;
    133
    134	return 0;
    135}
    136
    137static struct console bios_console = {
    138	.name		= "bios",
    139	.write		= sh_console_write,
    140	.setup		= sh_console_setup,
    141	.flags		= CON_PRINTBUFFER,
    142	.index		= -1,
    143};
    144
    145static int __init setup_early_printk(char *buf)
    146{
    147	int keep_early = 0;
    148
    149	if (!buf)
    150		return 0;
    151
    152	if (strstr(buf, "keep"))
    153		keep_early = 1;
    154
    155	if (!strncmp(buf, "bios", 4))
    156		early_console = &bios_console;
    157
    158	if (likely(early_console)) {
    159		if (keep_early)
    160			early_console->flags &= ~CON_BOOT;
    161		else
    162			early_console->flags |= CON_BOOT;
    163		register_console(early_console);
    164	}
    165
    166	return 0;
    167}
    168early_param("earlyprintk", setup_early_printk);
    169#endif