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

line.c (16380B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
      4 */
      5
      6#include <linux/irqreturn.h>
      7#include <linux/kd.h>
      8#include <linux/sched/signal.h>
      9#include <linux/slab.h>
     10
     11#include "chan.h"
     12#include <irq_kern.h>
     13#include <irq_user.h>
     14#include <kern_util.h>
     15#include <os.h>
     16
     17#define LINE_BUFSIZE 4096
     18
     19static irqreturn_t line_interrupt(int irq, void *data)
     20{
     21	struct chan *chan = data;
     22	struct line *line = chan->line;
     23
     24	if (line)
     25		chan_interrupt(line, irq);
     26
     27	return IRQ_HANDLED;
     28}
     29
     30/*
     31 * Returns the free space inside the ring buffer of this line.
     32 *
     33 * Should be called while holding line->lock (this does not modify data).
     34 */
     35static unsigned int write_room(struct line *line)
     36{
     37	int n;
     38
     39	if (line->buffer == NULL)
     40		return LINE_BUFSIZE - 1;
     41
     42	/* This is for the case where the buffer is wrapped! */
     43	n = line->head - line->tail;
     44
     45	if (n <= 0)
     46		n += LINE_BUFSIZE; /* The other case */
     47	return n - 1;
     48}
     49
     50unsigned int line_write_room(struct tty_struct *tty)
     51{
     52	struct line *line = tty->driver_data;
     53	unsigned long flags;
     54	unsigned int room;
     55
     56	spin_lock_irqsave(&line->lock, flags);
     57	room = write_room(line);
     58	spin_unlock_irqrestore(&line->lock, flags);
     59
     60	return room;
     61}
     62
     63unsigned int line_chars_in_buffer(struct tty_struct *tty)
     64{
     65	struct line *line = tty->driver_data;
     66	unsigned long flags;
     67	unsigned int ret;
     68
     69	spin_lock_irqsave(&line->lock, flags);
     70	/* write_room subtracts 1 for the needed NULL, so we readd it.*/
     71	ret = LINE_BUFSIZE - (write_room(line) + 1);
     72	spin_unlock_irqrestore(&line->lock, flags);
     73
     74	return ret;
     75}
     76
     77/*
     78 * This copies the content of buf into the circular buffer associated with
     79 * this line.
     80 * The return value is the number of characters actually copied, i.e. the ones
     81 * for which there was space: this function is not supposed to ever flush out
     82 * the circular buffer.
     83 *
     84 * Must be called while holding line->lock!
     85 */
     86static int buffer_data(struct line *line, const char *buf, int len)
     87{
     88	int end, room;
     89
     90	if (line->buffer == NULL) {
     91		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
     92		if (line->buffer == NULL) {
     93			printk(KERN_ERR "buffer_data - atomic allocation "
     94			       "failed\n");
     95			return 0;
     96		}
     97		line->head = line->buffer;
     98		line->tail = line->buffer;
     99	}
    100
    101	room = write_room(line);
    102	len = (len > room) ? room : len;
    103
    104	end = line->buffer + LINE_BUFSIZE - line->tail;
    105
    106	if (len < end) {
    107		memcpy(line->tail, buf, len);
    108		line->tail += len;
    109	}
    110	else {
    111		/* The circular buffer is wrapping */
    112		memcpy(line->tail, buf, end);
    113		buf += end;
    114		memcpy(line->buffer, buf, len - end);
    115		line->tail = line->buffer + len - end;
    116	}
    117
    118	return len;
    119}
    120
    121/*
    122 * Flushes the ring buffer to the output channels. That is, write_chan is
    123 * called, passing it line->head as buffer, and an appropriate count.
    124 *
    125 * On exit, returns 1 when the buffer is empty,
    126 * 0 when the buffer is not empty on exit,
    127 * and -errno when an error occurred.
    128 *
    129 * Must be called while holding line->lock!*/
    130static int flush_buffer(struct line *line)
    131{
    132	int n, count;
    133
    134	if ((line->buffer == NULL) || (line->head == line->tail))
    135		return 1;
    136
    137	if (line->tail < line->head) {
    138		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */
    139		count = line->buffer + LINE_BUFSIZE - line->head;
    140
    141		n = write_chan(line->chan_out, line->head, count,
    142			       line->write_irq);
    143		if (n < 0)
    144			return n;
    145		if (n == count) {
    146			/*
    147			 * We have flushed from ->head to buffer end, now we
    148			 * must flush only from the beginning to ->tail.
    149			 */
    150			line->head = line->buffer;
    151		} else {
    152			line->head += n;
    153			return 0;
    154		}
    155	}
    156
    157	count = line->tail - line->head;
    158	n = write_chan(line->chan_out, line->head, count,
    159		       line->write_irq);
    160
    161	if (n < 0)
    162		return n;
    163
    164	line->head += n;
    165	return line->head == line->tail;
    166}
    167
    168void line_flush_buffer(struct tty_struct *tty)
    169{
    170	struct line *line = tty->driver_data;
    171	unsigned long flags;
    172
    173	spin_lock_irqsave(&line->lock, flags);
    174	flush_buffer(line);
    175	spin_unlock_irqrestore(&line->lock, flags);
    176}
    177
    178/*
    179 * We map both ->flush_chars and ->put_char (which go in pair) onto
    180 * ->flush_buffer and ->write. Hope it's not that bad.
    181 */
    182void line_flush_chars(struct tty_struct *tty)
    183{
    184	line_flush_buffer(tty);
    185}
    186
    187int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
    188{
    189	struct line *line = tty->driver_data;
    190	unsigned long flags;
    191	int n, ret = 0;
    192
    193	spin_lock_irqsave(&line->lock, flags);
    194	if (line->head != line->tail)
    195		ret = buffer_data(line, buf, len);
    196	else {
    197		n = write_chan(line->chan_out, buf, len,
    198			       line->write_irq);
    199		if (n < 0) {
    200			ret = n;
    201			goto out_up;
    202		}
    203
    204		len -= n;
    205		ret += n;
    206		if (len > 0)
    207			ret += buffer_data(line, buf + n, len);
    208	}
    209out_up:
    210	spin_unlock_irqrestore(&line->lock, flags);
    211	return ret;
    212}
    213
    214void line_throttle(struct tty_struct *tty)
    215{
    216	struct line *line = tty->driver_data;
    217
    218	deactivate_chan(line->chan_in, line->read_irq);
    219	line->throttled = 1;
    220}
    221
    222void line_unthrottle(struct tty_struct *tty)
    223{
    224	struct line *line = tty->driver_data;
    225
    226	line->throttled = 0;
    227	chan_interrupt(line, line->read_irq);
    228}
    229
    230static irqreturn_t line_write_interrupt(int irq, void *data)
    231{
    232	struct chan *chan = data;
    233	struct line *line = chan->line;
    234	int err;
    235
    236	/*
    237	 * Interrupts are disabled here because genirq keep irqs disabled when
    238	 * calling the action handler.
    239	 */
    240
    241	spin_lock(&line->lock);
    242	err = flush_buffer(line);
    243	if (err == 0) {
    244		spin_unlock(&line->lock);
    245		return IRQ_NONE;
    246	} else if ((err < 0) && (err != -EAGAIN)) {
    247		line->head = line->buffer;
    248		line->tail = line->buffer;
    249	}
    250	spin_unlock(&line->lock);
    251
    252	tty_port_tty_wakeup(&line->port);
    253
    254	return IRQ_HANDLED;
    255}
    256
    257int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
    258{
    259	const struct line_driver *driver = line->driver;
    260	int err;
    261
    262	if (input) {
    263		err = um_request_irq(UM_IRQ_ALLOC, fd, IRQ_READ,
    264				     line_interrupt, 0,
    265				     driver->read_irq_name, data);
    266		if (err < 0)
    267			return err;
    268
    269		line->read_irq = err;
    270	}
    271
    272	if (output) {
    273		err = um_request_irq(UM_IRQ_ALLOC, fd, IRQ_WRITE,
    274				     line_write_interrupt, 0,
    275				     driver->write_irq_name, data);
    276		if (err < 0)
    277			return err;
    278
    279		line->write_irq = err;
    280	}
    281
    282	return 0;
    283}
    284
    285static int line_activate(struct tty_port *port, struct tty_struct *tty)
    286{
    287	int ret;
    288	struct line *line = tty->driver_data;
    289
    290	ret = enable_chan(line);
    291	if (ret)
    292		return ret;
    293
    294	if (!line->sigio) {
    295		chan_enable_winch(line->chan_out, port);
    296		line->sigio = 1;
    297	}
    298
    299	chan_window_size(line, &tty->winsize.ws_row,
    300		&tty->winsize.ws_col);
    301
    302	return 0;
    303}
    304
    305static void unregister_winch(struct tty_struct *tty);
    306
    307static void line_destruct(struct tty_port *port)
    308{
    309	struct tty_struct *tty = tty_port_tty_get(port);
    310	struct line *line = tty->driver_data;
    311
    312	if (line->sigio) {
    313		unregister_winch(tty);
    314		line->sigio = 0;
    315	}
    316}
    317
    318static const struct tty_port_operations line_port_ops = {
    319	.activate = line_activate,
    320	.destruct = line_destruct,
    321};
    322
    323int line_open(struct tty_struct *tty, struct file *filp)
    324{
    325	struct line *line = tty->driver_data;
    326
    327	return tty_port_open(&line->port, tty, filp);
    328}
    329
    330int line_install(struct tty_driver *driver, struct tty_struct *tty,
    331		 struct line *line)
    332{
    333	int ret;
    334
    335	ret = tty_standard_install(driver, tty);
    336	if (ret)
    337		return ret;
    338
    339	tty->driver_data = line;
    340
    341	return 0;
    342}
    343
    344void line_close(struct tty_struct *tty, struct file * filp)
    345{
    346	struct line *line = tty->driver_data;
    347
    348	tty_port_close(&line->port, tty, filp);
    349}
    350
    351void line_hangup(struct tty_struct *tty)
    352{
    353	struct line *line = tty->driver_data;
    354
    355	tty_port_hangup(&line->port);
    356}
    357
    358void close_lines(struct line *lines, int nlines)
    359{
    360	int i;
    361
    362	for(i = 0; i < nlines; i++)
    363		close_chan(&lines[i]);
    364}
    365
    366int setup_one_line(struct line *lines, int n, char *init,
    367		   const struct chan_opts *opts, char **error_out)
    368{
    369	struct line *line = &lines[n];
    370	struct tty_driver *driver = line->driver->driver;
    371	int err = -EINVAL;
    372
    373	if (line->port.count) {
    374		*error_out = "Device is already open";
    375		goto out;
    376	}
    377
    378	if (!strcmp(init, "none")) {
    379		if (line->valid) {
    380			line->valid = 0;
    381			kfree(line->init_str);
    382			tty_unregister_device(driver, n);
    383			parse_chan_pair(NULL, line, n, opts, error_out);
    384			err = 0;
    385		}
    386	} else {
    387		char *new = kstrdup(init, GFP_KERNEL);
    388		if (!new) {
    389			*error_out = "Failed to allocate memory";
    390			return -ENOMEM;
    391		}
    392		if (line->valid) {
    393			tty_unregister_device(driver, n);
    394			kfree(line->init_str);
    395		}
    396		line->init_str = new;
    397		line->valid = 1;
    398		err = parse_chan_pair(new, line, n, opts, error_out);
    399		if (!err) {
    400			struct device *d = tty_port_register_device(&line->port,
    401					driver, n, NULL);
    402			if (IS_ERR(d)) {
    403				*error_out = "Failed to register device";
    404				err = PTR_ERR(d);
    405				parse_chan_pair(NULL, line, n, opts, error_out);
    406			}
    407		}
    408		if (err) {
    409			line->init_str = NULL;
    410			line->valid = 0;
    411			kfree(new);
    412		}
    413	}
    414out:
    415	return err;
    416}
    417
    418/*
    419 * Common setup code for both startup command line and mconsole initialization.
    420 * @lines contains the array (of size @num) to modify;
    421 * @init is the setup string;
    422 * @error_out is an error string in the case of failure;
    423 */
    424
    425int line_setup(char **conf, unsigned int num, char **def,
    426	       char *init, char *name)
    427{
    428	char *error;
    429
    430	if (*init == '=') {
    431		/*
    432		 * We said con=/ssl= instead of con#=, so we are configuring all
    433		 * consoles at once.
    434		 */
    435		*def = init + 1;
    436	} else {
    437		char *end;
    438		unsigned n = simple_strtoul(init, &end, 0);
    439
    440		if (*end != '=') {
    441			error = "Couldn't parse device number";
    442			goto out;
    443		}
    444		if (n >= num) {
    445			error = "Device number out of range";
    446			goto out;
    447		}
    448		conf[n] = end + 1;
    449	}
    450	return 0;
    451
    452out:
    453	printk(KERN_ERR "Failed to set up %s with "
    454	       "configuration string \"%s\" : %s\n", name, init, error);
    455	return -EINVAL;
    456}
    457
    458int line_config(struct line *lines, unsigned int num, char *str,
    459		const struct chan_opts *opts, char **error_out)
    460{
    461	char *end;
    462	int n;
    463
    464	if (*str == '=') {
    465		*error_out = "Can't configure all devices from mconsole";
    466		return -EINVAL;
    467	}
    468
    469	n = simple_strtoul(str, &end, 0);
    470	if (*end++ != '=') {
    471		*error_out = "Couldn't parse device number";
    472		return -EINVAL;
    473	}
    474	if (n >= num) {
    475		*error_out = "Device number out of range";
    476		return -EINVAL;
    477	}
    478
    479	return setup_one_line(lines, n, end, opts, error_out);
    480}
    481
    482int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
    483		    int size, char **error_out)
    484{
    485	struct line *line;
    486	char *end;
    487	int dev, n = 0;
    488
    489	dev = simple_strtoul(name, &end, 0);
    490	if ((*end != '\0') || (end == name)) {
    491		*error_out = "line_get_config failed to parse device number";
    492		return 0;
    493	}
    494
    495	if ((dev < 0) || (dev >= num)) {
    496		*error_out = "device number out of range";
    497		return 0;
    498	}
    499
    500	line = &lines[dev];
    501
    502	if (!line->valid)
    503		CONFIG_CHUNK(str, size, n, "none", 1);
    504	else {
    505		struct tty_struct *tty = tty_port_tty_get(&line->port);
    506		if (tty == NULL) {
    507			CONFIG_CHUNK(str, size, n, line->init_str, 1);
    508		} else {
    509			n = chan_config_string(line, str, size, error_out);
    510			tty_kref_put(tty);
    511		}
    512	}
    513
    514	return n;
    515}
    516
    517int line_id(char **str, int *start_out, int *end_out)
    518{
    519	char *end;
    520	int n;
    521
    522	n = simple_strtoul(*str, &end, 0);
    523	if ((*end != '\0') || (end == *str))
    524		return -1;
    525
    526	*str = end;
    527	*start_out = n;
    528	*end_out = n;
    529	return n;
    530}
    531
    532int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
    533{
    534	if (n >= num) {
    535		*error_out = "Device number out of range";
    536		return -EINVAL;
    537	}
    538	return setup_one_line(lines, n, "none", NULL, error_out);
    539}
    540
    541int register_lines(struct line_driver *line_driver,
    542		   const struct tty_operations *ops,
    543		   struct line *lines, int nlines)
    544{
    545	struct tty_driver *driver;
    546	int err;
    547	int i;
    548
    549	driver = tty_alloc_driver(nlines, TTY_DRIVER_REAL_RAW |
    550			TTY_DRIVER_DYNAMIC_DEV);
    551	if (IS_ERR(driver))
    552		return PTR_ERR(driver);
    553
    554	driver->driver_name = line_driver->name;
    555	driver->name = line_driver->device_name;
    556	driver->major = line_driver->major;
    557	driver->minor_start = line_driver->minor_start;
    558	driver->type = line_driver->type;
    559	driver->subtype = line_driver->subtype;
    560	driver->init_termios = tty_std_termios;
    561
    562	for (i = 0; i < nlines; i++) {
    563		tty_port_init(&lines[i].port);
    564		lines[i].port.ops = &line_port_ops;
    565		spin_lock_init(&lines[i].lock);
    566		lines[i].driver = line_driver;
    567		INIT_LIST_HEAD(&lines[i].chan_list);
    568	}
    569	tty_set_operations(driver, ops);
    570
    571	err = tty_register_driver(driver);
    572	if (err) {
    573		printk(KERN_ERR "register_lines : can't register %s driver\n",
    574		       line_driver->name);
    575		tty_driver_kref_put(driver);
    576		for (i = 0; i < nlines; i++)
    577			tty_port_destroy(&lines[i].port);
    578		return err;
    579	}
    580
    581	line_driver->driver = driver;
    582	mconsole_register_dev(&line_driver->mc);
    583	return 0;
    584}
    585
    586static DEFINE_SPINLOCK(winch_handler_lock);
    587static LIST_HEAD(winch_handlers);
    588
    589struct winch {
    590	struct list_head list;
    591	int fd;
    592	int tty_fd;
    593	int pid;
    594	struct tty_port *port;
    595	unsigned long stack;
    596	struct work_struct work;
    597};
    598
    599static void __free_winch(struct work_struct *work)
    600{
    601	struct winch *winch = container_of(work, struct winch, work);
    602	um_free_irq(WINCH_IRQ, winch);
    603
    604	if (winch->pid != -1)
    605		os_kill_process(winch->pid, 1);
    606	if (winch->stack != 0)
    607		free_stack(winch->stack, 0);
    608	kfree(winch);
    609}
    610
    611static void free_winch(struct winch *winch)
    612{
    613	int fd = winch->fd;
    614	winch->fd = -1;
    615	if (fd != -1)
    616		os_close_file(fd);
    617	__free_winch(&winch->work);
    618}
    619
    620static irqreturn_t winch_interrupt(int irq, void *data)
    621{
    622	struct winch *winch = data;
    623	struct tty_struct *tty;
    624	struct line *line;
    625	int fd = winch->fd;
    626	int err;
    627	char c;
    628	struct pid *pgrp;
    629
    630	if (fd != -1) {
    631		err = generic_read(fd, &c, NULL);
    632		if (err < 0) {
    633			if (err != -EAGAIN) {
    634				winch->fd = -1;
    635				list_del(&winch->list);
    636				os_close_file(fd);
    637				printk(KERN_ERR "winch_interrupt : "
    638				       "read failed, errno = %d\n", -err);
    639				printk(KERN_ERR "fd %d is losing SIGWINCH "
    640				       "support\n", winch->tty_fd);
    641				INIT_WORK(&winch->work, __free_winch);
    642				schedule_work(&winch->work);
    643				return IRQ_HANDLED;
    644			}
    645			goto out;
    646		}
    647	}
    648	tty = tty_port_tty_get(winch->port);
    649	if (tty != NULL) {
    650		line = tty->driver_data;
    651		if (line != NULL) {
    652			chan_window_size(line, &tty->winsize.ws_row,
    653					 &tty->winsize.ws_col);
    654			pgrp = tty_get_pgrp(tty);
    655			if (pgrp)
    656				kill_pgrp(pgrp, SIGWINCH, 1);
    657			put_pid(pgrp);
    658		}
    659		tty_kref_put(tty);
    660	}
    661 out:
    662	return IRQ_HANDLED;
    663}
    664
    665void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port,
    666			unsigned long stack)
    667{
    668	struct winch *winch;
    669
    670	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
    671	if (winch == NULL) {
    672		printk(KERN_ERR "register_winch_irq - kmalloc failed\n");
    673		goto cleanup;
    674	}
    675
    676	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
    677				   .fd  	= fd,
    678				   .tty_fd 	= tty_fd,
    679				   .pid  	= pid,
    680				   .port 	= port,
    681				   .stack	= stack });
    682
    683	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
    684			   IRQF_SHARED, "winch", winch) < 0) {
    685		printk(KERN_ERR "register_winch_irq - failed to register "
    686		       "IRQ\n");
    687		goto out_free;
    688	}
    689
    690	spin_lock(&winch_handler_lock);
    691	list_add(&winch->list, &winch_handlers);
    692	spin_unlock(&winch_handler_lock);
    693
    694	return;
    695
    696 out_free:
    697	kfree(winch);
    698 cleanup:
    699	os_kill_process(pid, 1);
    700	os_close_file(fd);
    701	if (stack != 0)
    702		free_stack(stack, 0);
    703}
    704
    705static void unregister_winch(struct tty_struct *tty)
    706{
    707	struct list_head *ele, *next;
    708	struct winch *winch;
    709	struct tty_struct *wtty;
    710
    711	spin_lock(&winch_handler_lock);
    712
    713	list_for_each_safe(ele, next, &winch_handlers) {
    714		winch = list_entry(ele, struct winch, list);
    715		wtty = tty_port_tty_get(winch->port);
    716		if (wtty == tty) {
    717			list_del(&winch->list);
    718			spin_unlock(&winch_handler_lock);
    719			free_winch(winch);
    720			break;
    721		}
    722		tty_kref_put(wtty);
    723	}
    724	spin_unlock(&winch_handler_lock);
    725}
    726
    727static void winch_cleanup(void)
    728{
    729	struct winch *winch;
    730
    731	spin_lock(&winch_handler_lock);
    732	while ((winch = list_first_entry_or_null(&winch_handlers,
    733						 struct winch, list))) {
    734		list_del(&winch->list);
    735		spin_unlock(&winch_handler_lock);
    736
    737		free_winch(winch);
    738
    739		spin_lock(&winch_handler_lock);
    740	}
    741
    742	spin_unlock(&winch_handler_lock);
    743}
    744__uml_exitcall(winch_cleanup);
    745
    746char *add_xterm_umid(char *base)
    747{
    748	char *umid, *title;
    749	int len;
    750
    751	umid = get_umid();
    752	if (*umid == '\0')
    753		return base;
    754
    755	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
    756	title = kmalloc(len, GFP_KERNEL);
    757	if (title == NULL) {
    758		printk(KERN_ERR "Failed to allocate buffer for xterm title\n");
    759		return base;
    760	}
    761
    762	snprintf(title, len, "%s (%s)", base, umid);
    763	return title;
    764}