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

w1_ds28e04.c (9576B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	w1_ds28e04.c - w1 family 1C (DS28E04) driver
      4 *
      5 * Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/moduleparam.h>
     11#include <linux/device.h>
     12#include <linux/types.h>
     13#include <linux/delay.h>
     14#include <linux/slab.h>
     15#include <linux/crc16.h>
     16#include <linux/uaccess.h>
     17
     18#define CRC16_INIT		0
     19#define CRC16_VALID		0xb001
     20
     21#include <linux/w1.h>
     22
     23#define W1_FAMILY_DS28E04	0x1C
     24
     25/* Allow the strong pullup to be disabled, but default to enabled.
     26 * If it was disabled a parasite powered device might not get the required
     27 * current to copy the data from the scratchpad to EEPROM.  If it is enabled
     28 * parasite powered devices have a better chance of getting the current
     29 * required.
     30 */
     31static int w1_strong_pullup = 1;
     32module_param_named(strong_pullup, w1_strong_pullup, int, 0);
     33
     34/* enable/disable CRC checking on DS28E04-100 memory accesses */
     35static bool w1_enable_crccheck = true;
     36
     37#define W1_EEPROM_SIZE		512
     38#define W1_PAGE_COUNT		16
     39#define W1_PAGE_SIZE		32
     40#define W1_PAGE_BITS		5
     41#define W1_PAGE_MASK		0x1F
     42
     43#define W1_F1C_READ_EEPROM	0xF0
     44#define W1_F1C_WRITE_SCRATCH	0x0F
     45#define W1_F1C_READ_SCRATCH	0xAA
     46#define W1_F1C_COPY_SCRATCH	0x55
     47#define W1_F1C_ACCESS_WRITE	0x5A
     48
     49#define W1_1C_REG_LOGIC_STATE	0x220
     50
     51struct w1_f1C_data {
     52	u8	memory[W1_EEPROM_SIZE];
     53	u32	validcrc;
     54};
     55
     56/**
     57 * Check the file size bounds and adjusts count as needed.
     58 * This would not be needed if the file size didn't reset to 0 after a write.
     59 */
     60static inline size_t w1_f1C_fix_count(loff_t off, size_t count, size_t size)
     61{
     62	if (off > size)
     63		return 0;
     64
     65	if ((off + count) > size)
     66		return size - off;
     67
     68	return count;
     69}
     70
     71static int w1_f1C_refresh_block(struct w1_slave *sl, struct w1_f1C_data *data,
     72				int block)
     73{
     74	u8	wrbuf[3];
     75	int	off = block * W1_PAGE_SIZE;
     76
     77	if (data->validcrc & (1 << block))
     78		return 0;
     79
     80	if (w1_reset_select_slave(sl)) {
     81		data->validcrc = 0;
     82		return -EIO;
     83	}
     84
     85	wrbuf[0] = W1_F1C_READ_EEPROM;
     86	wrbuf[1] = off & 0xff;
     87	wrbuf[2] = off >> 8;
     88	w1_write_block(sl->master, wrbuf, 3);
     89	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
     90
     91	/* cache the block if the CRC is valid */
     92	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
     93		data->validcrc |= (1 << block);
     94
     95	return 0;
     96}
     97
     98static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data)
     99{
    100	u8 wrbuf[3];
    101
    102	/* read directly from the EEPROM */
    103	if (w1_reset_select_slave(sl))
    104		return -EIO;
    105
    106	wrbuf[0] = W1_F1C_READ_EEPROM;
    107	wrbuf[1] = addr & 0xff;
    108	wrbuf[2] = addr >> 8;
    109
    110	w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
    111	return w1_read_block(sl->master, data, len);
    112}
    113
    114static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
    115			   struct bin_attribute *bin_attr, char *buf,
    116			   loff_t off, size_t count)
    117{
    118	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    119	struct w1_f1C_data *data = sl->family_data;
    120	int i, min_page, max_page;
    121
    122	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
    123	if (count == 0)
    124		return 0;
    125
    126	mutex_lock(&sl->master->mutex);
    127
    128	if (w1_enable_crccheck) {
    129		min_page = (off >> W1_PAGE_BITS);
    130		max_page = (off + count - 1) >> W1_PAGE_BITS;
    131		for (i = min_page; i <= max_page; i++) {
    132			if (w1_f1C_refresh_block(sl, data, i)) {
    133				count = -EIO;
    134				goto out_up;
    135			}
    136		}
    137		memcpy(buf, &data->memory[off], count);
    138	} else {
    139		count = w1_f1C_read(sl, off, count, buf);
    140	}
    141
    142out_up:
    143	mutex_unlock(&sl->master->mutex);
    144
    145	return count;
    146}
    147
    148/**
    149 * Writes to the scratchpad and reads it back for verification.
    150 * Then copies the scratchpad to EEPROM.
    151 * The data must be on one page.
    152 * The master must be locked.
    153 *
    154 * @param sl	The slave structure
    155 * @param addr	Address for the write
    156 * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
    157 * @param data	The data to write
    158 * @return	0=Success -1=failure
    159 */
    160static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data)
    161{
    162	u8 wrbuf[4];
    163	u8 rdbuf[W1_PAGE_SIZE + 3];
    164	u8 es = (addr + len - 1) & 0x1f;
    165	unsigned int tm = 10;
    166	int i;
    167	struct w1_f1C_data *f1C = sl->family_data;
    168
    169	/* Write the data to the scratchpad */
    170	if (w1_reset_select_slave(sl))
    171		return -1;
    172
    173	wrbuf[0] = W1_F1C_WRITE_SCRATCH;
    174	wrbuf[1] = addr & 0xff;
    175	wrbuf[2] = addr >> 8;
    176
    177	w1_write_block(sl->master, wrbuf, 3);
    178	w1_write_block(sl->master, data, len);
    179
    180	/* Read the scratchpad and verify */
    181	if (w1_reset_select_slave(sl))
    182		return -1;
    183
    184	w1_write_8(sl->master, W1_F1C_READ_SCRATCH);
    185	w1_read_block(sl->master, rdbuf, len + 3);
    186
    187	/* Compare what was read against the data written */
    188	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
    189	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
    190		return -1;
    191
    192	/* Copy the scratchpad to EEPROM */
    193	if (w1_reset_select_slave(sl))
    194		return -1;
    195
    196	wrbuf[0] = W1_F1C_COPY_SCRATCH;
    197	wrbuf[3] = es;
    198
    199	for (i = 0; i < sizeof(wrbuf); ++i) {
    200		/* issue 10ms strong pullup (or delay) on the last byte
    201		   for writing the data from the scratchpad to EEPROM */
    202		if (w1_strong_pullup && i == sizeof(wrbuf)-1)
    203			w1_next_pullup(sl->master, tm);
    204
    205		w1_write_8(sl->master, wrbuf[i]);
    206	}
    207
    208	if (!w1_strong_pullup)
    209		msleep(tm);
    210
    211	if (w1_enable_crccheck) {
    212		/* invalidate cached data */
    213		f1C->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
    214	}
    215
    216	/* Reset the bus to wake up the EEPROM (this may not be needed) */
    217	w1_reset_bus(sl->master);
    218
    219	return 0;
    220}
    221
    222static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
    223			    struct bin_attribute *bin_attr, char *buf,
    224			    loff_t off, size_t count)
    225
    226{
    227	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    228	int addr, len, idx;
    229
    230	count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
    231	if (count == 0)
    232		return 0;
    233
    234	if (w1_enable_crccheck) {
    235		/* can only write full blocks in cached mode */
    236		if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
    237			dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
    238				(int)off, count);
    239			return -EINVAL;
    240		}
    241
    242		/* make sure the block CRCs are valid */
    243		for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
    244			if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE)
    245				!= CRC16_VALID) {
    246				dev_err(&sl->dev, "bad CRC at offset %d\n",
    247					(int)off);
    248				return -EINVAL;
    249			}
    250		}
    251	}
    252
    253	mutex_lock(&sl->master->mutex);
    254
    255	/* Can only write data to one page at a time */
    256	idx = 0;
    257	while (idx < count) {
    258		addr = off + idx;
    259		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
    260		if (len > (count - idx))
    261			len = count - idx;
    262
    263		if (w1_f1C_write(sl, addr, len, &buf[idx]) < 0) {
    264			count = -EIO;
    265			goto out_up;
    266		}
    267		idx += len;
    268	}
    269
    270out_up:
    271	mutex_unlock(&sl->master->mutex);
    272
    273	return count;
    274}
    275
    276static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
    277
    278static ssize_t pio_read(struct file *filp, struct kobject *kobj,
    279			struct bin_attribute *bin_attr, char *buf, loff_t off,
    280			size_t count)
    281
    282{
    283	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    284	int ret;
    285
    286	/* check arguments */
    287	if (off != 0 || count != 1 || buf == NULL)
    288		return -EINVAL;
    289
    290	mutex_lock(&sl->master->mutex);
    291	ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf);
    292	mutex_unlock(&sl->master->mutex);
    293
    294	return ret;
    295}
    296
    297static ssize_t pio_write(struct file *filp, struct kobject *kobj,
    298			 struct bin_attribute *bin_attr, char *buf, loff_t off,
    299			 size_t count)
    300
    301{
    302	struct w1_slave *sl = kobj_to_w1_slave(kobj);
    303	u8 wrbuf[3];
    304	u8 ack;
    305
    306	/* check arguments */
    307	if (off != 0 || count != 1 || buf == NULL)
    308		return -EINVAL;
    309
    310	mutex_lock(&sl->master->mutex);
    311
    312	/* Write the PIO data */
    313	if (w1_reset_select_slave(sl)) {
    314		mutex_unlock(&sl->master->mutex);
    315		return -1;
    316	}
    317
    318	/* set bit 7..2 to value '1' */
    319	*buf = *buf | 0xFC;
    320
    321	wrbuf[0] = W1_F1C_ACCESS_WRITE;
    322	wrbuf[1] = *buf;
    323	wrbuf[2] = ~(*buf);
    324	w1_write_block(sl->master, wrbuf, 3);
    325
    326	w1_read_block(sl->master, &ack, sizeof(ack));
    327
    328	mutex_unlock(&sl->master->mutex);
    329
    330	/* check for acknowledgement */
    331	if (ack != 0xAA)
    332		return -EIO;
    333
    334	return count;
    335}
    336
    337static BIN_ATTR_RW(pio, 1);
    338
    339static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr,
    340			     char *buf)
    341{
    342	return sysfs_emit(buf, "%d\n", w1_enable_crccheck);
    343}
    344
    345static ssize_t crccheck_store(struct device *dev, struct device_attribute *attr,
    346			      const char *buf, size_t count)
    347{
    348	int err = kstrtobool(buf, &w1_enable_crccheck);
    349
    350	if (err)
    351		return err;
    352
    353	return count;
    354}
    355
    356static DEVICE_ATTR_RW(crccheck);
    357
    358static struct attribute *w1_f1C_attrs[] = {
    359	&dev_attr_crccheck.attr,
    360	NULL,
    361};
    362
    363static struct bin_attribute *w1_f1C_bin_attrs[] = {
    364	&bin_attr_eeprom,
    365	&bin_attr_pio,
    366	NULL,
    367};
    368
    369static const struct attribute_group w1_f1C_group = {
    370	.attrs		= w1_f1C_attrs,
    371	.bin_attrs	= w1_f1C_bin_attrs,
    372};
    373
    374static const struct attribute_group *w1_f1C_groups[] = {
    375	&w1_f1C_group,
    376	NULL,
    377};
    378
    379static int w1_f1C_add_slave(struct w1_slave *sl)
    380{
    381	struct w1_f1C_data *data = NULL;
    382
    383	if (w1_enable_crccheck) {
    384		data = kzalloc(sizeof(struct w1_f1C_data), GFP_KERNEL);
    385		if (!data)
    386			return -ENOMEM;
    387		sl->family_data = data;
    388	}
    389
    390	return 0;
    391}
    392
    393static void w1_f1C_remove_slave(struct w1_slave *sl)
    394{
    395	kfree(sl->family_data);
    396	sl->family_data = NULL;
    397}
    398
    399static const struct w1_family_ops w1_f1C_fops = {
    400	.add_slave      = w1_f1C_add_slave,
    401	.remove_slave   = w1_f1C_remove_slave,
    402	.groups		= w1_f1C_groups,
    403};
    404
    405static struct w1_family w1_family_1C = {
    406	.fid = W1_FAMILY_DS28E04,
    407	.fops = &w1_f1C_fops,
    408};
    409module_w1_family(w1_family_1C);
    410
    411MODULE_AUTHOR("Markus Franke <franke.m@sebakmt.com>, <franm@hrz.tu-chemnitz.de>");
    412MODULE_DESCRIPTION("w1 family 1C driver for DS28E04, 4kb EEPROM and PIO");
    413MODULE_LICENSE("GPL");
    414MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E04));