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

ans-lcd.c (4108B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * /dev/lcd driver for Apple Network Servers.
      4 */
      5
      6#include <linux/types.h>
      7#include <linux/errno.h>
      8#include <linux/kernel.h>
      9#include <linux/miscdevice.h>
     10#include <linux/fcntl.h>
     11#include <linux/module.h>
     12#include <linux/delay.h>
     13#include <linux/fs.h>
     14#include <linux/of.h>
     15
     16#include <linux/uaccess.h>
     17#include <asm/sections.h>
     18#include <asm/io.h>
     19
     20#include "ans-lcd.h"
     21
     22#define ANSLCD_ADDR		0xf301c000
     23#define ANSLCD_CTRL_IX 0x00
     24#define ANSLCD_DATA_IX 0x10
     25
     26static unsigned long anslcd_short_delay = 80;
     27static unsigned long anslcd_long_delay = 3280;
     28static volatile unsigned char __iomem *anslcd_ptr;
     29static DEFINE_MUTEX(anslcd_mutex);
     30
     31#undef DEBUG
     32
     33static void
     34anslcd_write_byte_ctrl ( unsigned char c )
     35{
     36#ifdef DEBUG
     37	printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c);
     38#endif
     39	out_8(anslcd_ptr + ANSLCD_CTRL_IX, c);
     40	switch(c) {
     41		case 1:
     42		case 2:
     43		case 3:
     44			udelay(anslcd_long_delay); break;
     45		default: udelay(anslcd_short_delay);
     46	}
     47}
     48
     49static void
     50anslcd_write_byte_data ( unsigned char c )
     51{
     52	out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
     53	udelay(anslcd_short_delay);
     54}
     55
     56static ssize_t
     57anslcd_write( struct file * file, const char __user * buf, 
     58				size_t count, loff_t *ppos )
     59{
     60	const char __user *p = buf;
     61	int i;
     62
     63#ifdef DEBUG
     64	printk(KERN_DEBUG "LCD: write\n");
     65#endif
     66
     67	if (!access_ok(buf, count))
     68		return -EFAULT;
     69
     70	mutex_lock(&anslcd_mutex);
     71	for ( i = *ppos; count > 0; ++i, ++p, --count ) 
     72	{
     73		char c;
     74		__get_user(c, p);
     75		anslcd_write_byte_data( c );
     76	}
     77	mutex_unlock(&anslcd_mutex);
     78	*ppos = i;
     79	return p - buf;
     80}
     81
     82static long
     83anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     84{
     85	char ch, __user *temp;
     86	long ret = 0;
     87
     88#ifdef DEBUG
     89	printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
     90#endif
     91
     92	mutex_lock(&anslcd_mutex);
     93
     94	switch ( cmd )
     95	{
     96	case ANSLCD_CLEAR:
     97		anslcd_write_byte_ctrl ( 0x38 );
     98		anslcd_write_byte_ctrl ( 0x0f );
     99		anslcd_write_byte_ctrl ( 0x06 );
    100		anslcd_write_byte_ctrl ( 0x01 );
    101		anslcd_write_byte_ctrl ( 0x02 );
    102		break;
    103	case ANSLCD_SENDCTRL:
    104		temp = (char __user *) arg;
    105		__get_user(ch, temp);
    106		for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
    107			anslcd_write_byte_ctrl ( ch );
    108			__get_user(ch, temp);
    109		}
    110		break;
    111	case ANSLCD_SETSHORTDELAY:
    112		if (!capable(CAP_SYS_ADMIN))
    113			ret =-EACCES;
    114		else
    115			anslcd_short_delay=arg;
    116		break;
    117	case ANSLCD_SETLONGDELAY:
    118		if (!capable(CAP_SYS_ADMIN))
    119			ret = -EACCES;
    120		else
    121			anslcd_long_delay=arg;
    122		break;
    123	default:
    124		ret = -EINVAL;
    125	}
    126
    127	mutex_unlock(&anslcd_mutex);
    128	return ret;
    129}
    130
    131static int
    132anslcd_open( struct inode * inode, struct file * file )
    133{
    134	return 0;
    135}
    136
    137const struct file_operations anslcd_fops = {
    138	.write		= anslcd_write,
    139	.unlocked_ioctl	= anslcd_ioctl,
    140	.open		= anslcd_open,
    141	.llseek		= default_llseek,
    142};
    143
    144static struct miscdevice anslcd_dev = {
    145	LCD_MINOR,
    146	"anslcd",
    147	&anslcd_fops
    148};
    149
    150static const char anslcd_logo[] __initconst =
    151				"********************"  /* Line #1 */
    152				"*      LINUX!      *"  /* Line #3 */
    153				"*    Welcome to    *"  /* Line #2 */
    154				"********************"; /* Line #4 */
    155
    156static int __init
    157anslcd_init(void)
    158{
    159	int a;
    160	int retval;
    161	struct device_node* node;
    162
    163	node = of_find_node_by_name(NULL, "lcd");
    164	if (!node || !of_node_name_eq(node->parent, "gc")) {
    165		of_node_put(node);
    166		return -ENODEV;
    167	}
    168	of_node_put(node);
    169
    170	anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
    171	
    172	retval = misc_register(&anslcd_dev);
    173	if(retval < 0){
    174		printk(KERN_INFO "LCD: misc_register failed\n");
    175		iounmap(anslcd_ptr);
    176		return retval;
    177	}
    178
    179#ifdef DEBUG
    180	printk(KERN_DEBUG "LCD: init\n");
    181#endif
    182
    183	mutex_lock(&anslcd_mutex);
    184	anslcd_write_byte_ctrl ( 0x38 );
    185	anslcd_write_byte_ctrl ( 0x0c );
    186	anslcd_write_byte_ctrl ( 0x06 );
    187	anslcd_write_byte_ctrl ( 0x01 );
    188	anslcd_write_byte_ctrl ( 0x02 );
    189	for(a=0;a<80;a++) {
    190		anslcd_write_byte_data(anslcd_logo[a]);
    191	}
    192	mutex_unlock(&anslcd_mutex);
    193	return 0;
    194}
    195
    196static void __exit
    197anslcd_exit(void)
    198{
    199	misc_deregister(&anslcd_dev);
    200	iounmap(anslcd_ptr);
    201}
    202
    203module_init(anslcd_init);
    204module_exit(anslcd_exit);
    205MODULE_LICENSE("GPL v2");