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

srmcons.c (6115B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *	linux/arch/alpha/kernel/srmcons.c
      4 *
      5 * Callback based driver for SRM Console console device.
      6 * (TTY driver and console driver)
      7 */
      8
      9#include <linux/kernel.h>
     10#include <linux/init.h>
     11#include <linux/console.h>
     12#include <linux/delay.h>
     13#include <linux/mm.h>
     14#include <linux/slab.h>
     15#include <linux/spinlock.h>
     16#include <linux/timer.h>
     17#include <linux/tty.h>
     18#include <linux/tty_driver.h>
     19#include <linux/tty_flip.h>
     20
     21#include <asm/console.h>
     22#include <linux/uaccess.h>
     23
     24
     25static DEFINE_SPINLOCK(srmcons_callback_lock);
     26static int srm_is_registered_console = 0;
     27
     28/* 
     29 * The TTY driver
     30 */
     31#define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
     32
     33struct srmcons_private {
     34	struct tty_port port;
     35	struct timer_list timer;
     36} srmcons_singleton;
     37
     38typedef union _srmcons_result {
     39	struct {
     40		unsigned long c :61;
     41		unsigned long status :3;
     42	} bits;
     43	long as_long;
     44} srmcons_result;
     45
     46/* called with callback_lock held */
     47static int
     48srmcons_do_receive_chars(struct tty_port *port)
     49{
     50	srmcons_result result;
     51	int count = 0, loops = 0;
     52
     53	do {
     54		result.as_long = callback_getc(0);
     55		if (result.bits.status < 2) {
     56			tty_insert_flip_char(port, (char)result.bits.c, 0);
     57			count++;
     58		}
     59	} while((result.bits.status & 1) && (++loops < 10));
     60
     61	if (count)
     62		tty_flip_buffer_push(port);
     63
     64	return count;
     65}
     66
     67static void
     68srmcons_receive_chars(struct timer_list *t)
     69{
     70	struct srmcons_private *srmconsp = from_timer(srmconsp, t, timer);
     71	struct tty_port *port = &srmconsp->port;
     72	unsigned long flags;
     73	int incr = 10;
     74
     75	local_irq_save(flags);
     76	if (spin_trylock(&srmcons_callback_lock)) {
     77		if (!srmcons_do_receive_chars(port))
     78			incr = 100;
     79		spin_unlock(&srmcons_callback_lock);
     80	} 
     81
     82	spin_lock(&port->lock);
     83	if (port->tty)
     84		mod_timer(&srmconsp->timer, jiffies + incr);
     85	spin_unlock(&port->lock);
     86
     87	local_irq_restore(flags);
     88}
     89
     90/* called with callback_lock held */
     91static int
     92srmcons_do_write(struct tty_port *port, const char *buf, int count)
     93{
     94	static char str_cr[1] = "\r";
     95	long c, remaining = count;
     96	srmcons_result result;
     97	char *cur;
     98	int need_cr;
     99
    100	for (cur = (char *)buf; remaining > 0; ) {
    101		need_cr = 0;
    102		/* 
    103		 * Break it up into reasonable size chunks to allow a chance
    104		 * for input to get in
    105		 */
    106		for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
    107			if (cur[c] == '\n')
    108				need_cr = 1;
    109		
    110		while (c > 0) {
    111			result.as_long = callback_puts(0, cur, c);
    112			c -= result.bits.c;
    113			remaining -= result.bits.c;
    114			cur += result.bits.c;
    115
    116			/*
    117			 * Check for pending input iff a tty port was provided
    118			 */
    119			if (port)
    120				srmcons_do_receive_chars(port);
    121		}
    122
    123		while (need_cr) {
    124			result.as_long = callback_puts(0, str_cr, 1);
    125			if (result.bits.c > 0)
    126				need_cr = 0;
    127		}
    128	}
    129	return count;
    130}
    131
    132static int
    133srmcons_write(struct tty_struct *tty,
    134	      const unsigned char *buf, int count)
    135{
    136	unsigned long flags;
    137
    138	spin_lock_irqsave(&srmcons_callback_lock, flags);
    139	srmcons_do_write(tty->port, (const char *) buf, count);
    140	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
    141
    142	return count;
    143}
    144
    145static unsigned int
    146srmcons_write_room(struct tty_struct *tty)
    147{
    148	return 512;
    149}
    150
    151static int
    152srmcons_open(struct tty_struct *tty, struct file *filp)
    153{
    154	struct srmcons_private *srmconsp = &srmcons_singleton;
    155	struct tty_port *port = &srmconsp->port;
    156	unsigned long flags;
    157
    158	spin_lock_irqsave(&port->lock, flags);
    159
    160	if (!port->tty) {
    161		tty->driver_data = srmconsp;
    162		tty->port = port;
    163		port->tty = tty; /* XXX proper refcounting */
    164		mod_timer(&srmconsp->timer, jiffies + 10);
    165	}
    166
    167	spin_unlock_irqrestore(&port->lock, flags);
    168
    169	return 0;
    170}
    171
    172static void
    173srmcons_close(struct tty_struct *tty, struct file *filp)
    174{
    175	struct srmcons_private *srmconsp = tty->driver_data;
    176	struct tty_port *port = &srmconsp->port;
    177	unsigned long flags;
    178
    179	spin_lock_irqsave(&port->lock, flags);
    180
    181	if (tty->count == 1) {
    182		port->tty = NULL;
    183		del_timer(&srmconsp->timer);
    184	}
    185
    186	spin_unlock_irqrestore(&port->lock, flags);
    187}
    188
    189
    190static struct tty_driver *srmcons_driver;
    191
    192static const struct tty_operations srmcons_ops = {
    193	.open		= srmcons_open,
    194	.close		= srmcons_close,
    195	.write		= srmcons_write,
    196	.write_room	= srmcons_write_room,
    197};
    198
    199static int __init
    200srmcons_init(void)
    201{
    202	timer_setup(&srmcons_singleton.timer, srmcons_receive_chars, 0);
    203	if (srm_is_registered_console) {
    204		struct tty_driver *driver;
    205		int err;
    206
    207		driver = tty_alloc_driver(MAX_SRM_CONSOLE_DEVICES, 0);
    208		if (IS_ERR(driver))
    209			return PTR_ERR(driver);
    210
    211		tty_port_init(&srmcons_singleton.port);
    212
    213		driver->driver_name = "srm";
    214		driver->name = "srm";
    215		driver->major = 0; 	/* dynamic */
    216		driver->minor_start = 0;
    217		driver->type = TTY_DRIVER_TYPE_SYSTEM;
    218		driver->subtype = SYSTEM_TYPE_SYSCONS;
    219		driver->init_termios = tty_std_termios;
    220		tty_set_operations(driver, &srmcons_ops);
    221		tty_port_link_device(&srmcons_singleton.port, driver, 0);
    222		err = tty_register_driver(driver);
    223		if (err) {
    224			tty_driver_kref_put(driver);
    225			tty_port_destroy(&srmcons_singleton.port);
    226			return err;
    227		}
    228		srmcons_driver = driver;
    229	}
    230
    231	return -ENODEV;
    232}
    233device_initcall(srmcons_init);
    234
    235
    236/*
    237 * The console driver
    238 */
    239static void
    240srm_console_write(struct console *co, const char *s, unsigned count)
    241{
    242	unsigned long flags;
    243
    244	spin_lock_irqsave(&srmcons_callback_lock, flags);
    245	srmcons_do_write(NULL, s, count);
    246	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
    247}
    248
    249static struct tty_driver *
    250srm_console_device(struct console *co, int *index)
    251{
    252	*index = co->index;
    253	return srmcons_driver;
    254}
    255
    256static int
    257srm_console_setup(struct console *co, char *options)
    258{
    259	return 0;
    260}
    261
    262static struct console srmcons = {
    263	.name		= "srm",
    264	.write		= srm_console_write,
    265	.device		= srm_console_device,
    266	.setup		= srm_console_setup,
    267	.flags		= CON_PRINTBUFFER | CON_BOOT,
    268	.index		= -1,
    269};
    270
    271void __init
    272register_srm_console(void)
    273{
    274	if (!srm_is_registered_console) {
    275		callback_open_console();
    276		register_console(&srmcons);
    277		srm_is_registered_console = 1;
    278	}
    279}
    280
    281void __init
    282unregister_srm_console(void)
    283{
    284	if (srm_is_registered_console) {
    285		callback_close_console();
    286		unregister_console(&srmcons);
    287		srm_is_registered_console = 0;
    288	}
    289}