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

firmware.c (10053B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Linux driver for TerraTec DMX 6Fire USB
      4 *
      5 * Firmware loader
      6 *
      7 * Author:	Torsten Schenk <torsten.schenk@zoho.com>
      8 * Created:	Jan 01, 2011
      9 * Copyright:	(C) Torsten Schenk
     10 */
     11
     12#include <linux/firmware.h>
     13#include <linux/module.h>
     14#include <linux/bitrev.h>
     15#include <linux/kernel.h>
     16
     17#include "firmware.h"
     18#include "chip.h"
     19
     20MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
     21MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
     22MODULE_FIRMWARE("6fire/dmx6firecf.bin");
     23
     24enum {
     25	FPGA_BUFSIZE = 512, FPGA_EP = 2
     26};
     27
     28/*
     29 * wMaxPacketSize of pcm endpoints.
     30 * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
     31 * fpp: frames per isopacket
     32 *
     33 * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
     34 */
     35static const u8 ep_w_max_packet_size[] = {
     36	0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
     37	0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
     38	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
     39};
     40
     41static const u8 known_fw_versions[][2] = {
     42	{ 0x03, 0x01 }
     43};
     44
     45struct ihex_record {
     46	u16 address;
     47	u8 len;
     48	u8 data[256];
     49	char error; /* true if an error occurred parsing this record */
     50
     51	u8 max_len; /* maximum record length in whole ihex */
     52
     53	/* private */
     54	const char *txt_data;
     55	unsigned int txt_length;
     56	unsigned int txt_offset; /* current position in txt_data */
     57};
     58
     59static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
     60{
     61	u8 val = 0;
     62	int hval;
     63
     64	hval = hex_to_bin(data[0]);
     65	if (hval >= 0)
     66		val |= (hval << 4);
     67
     68	hval = hex_to_bin(data[1]);
     69	if (hval >= 0)
     70		val |= hval;
     71
     72	*crc += val;
     73	return val;
     74}
     75
     76/*
     77 * returns true if record is available, false otherwise.
     78 * iff an error occurred, false will be returned and record->error will be true.
     79 */
     80static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
     81{
     82	u8 crc = 0;
     83	u8 type;
     84	int i;
     85
     86	record->error = false;
     87
     88	/* find begin of record (marked by a colon) */
     89	while (record->txt_offset < record->txt_length
     90			&& record->txt_data[record->txt_offset] != ':')
     91		record->txt_offset++;
     92	if (record->txt_offset == record->txt_length)
     93		return false;
     94
     95	/* number of characters needed for len, addr and type entries */
     96	record->txt_offset++;
     97	if (record->txt_offset + 8 > record->txt_length) {
     98		record->error = true;
     99		return false;
    100	}
    101
    102	record->len = usb6fire_fw_ihex_hex(record->txt_data +
    103			record->txt_offset, &crc);
    104	record->txt_offset += 2;
    105	record->address = usb6fire_fw_ihex_hex(record->txt_data +
    106			record->txt_offset, &crc) << 8;
    107	record->txt_offset += 2;
    108	record->address |= usb6fire_fw_ihex_hex(record->txt_data +
    109			record->txt_offset, &crc);
    110	record->txt_offset += 2;
    111	type = usb6fire_fw_ihex_hex(record->txt_data +
    112			record->txt_offset, &crc);
    113	record->txt_offset += 2;
    114
    115	/* number of characters needed for data and crc entries */
    116	if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
    117		record->error = true;
    118		return false;
    119	}
    120	for (i = 0; i < record->len; i++) {
    121		record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
    122				+ record->txt_offset, &crc);
    123		record->txt_offset += 2;
    124	}
    125	usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
    126	if (crc) {
    127		record->error = true;
    128		return false;
    129	}
    130
    131	if (type == 1 || !record->len) /* eof */
    132		return false;
    133	else if (type == 0)
    134		return true;
    135	else {
    136		record->error = true;
    137		return false;
    138	}
    139}
    140
    141static int usb6fire_fw_ihex_init(const struct firmware *fw,
    142		struct ihex_record *record)
    143{
    144	record->txt_data = fw->data;
    145	record->txt_length = fw->size;
    146	record->txt_offset = 0;
    147	record->max_len = 0;
    148	/* read all records, if loop ends, record->error indicates,
    149	 * whether ihex is valid. */
    150	while (usb6fire_fw_ihex_next_record(record))
    151		record->max_len = max(record->len, record->max_len);
    152	if (record->error)
    153		return -EINVAL;
    154	record->txt_offset = 0;
    155	return 0;
    156}
    157
    158static int usb6fire_fw_ezusb_write(struct usb_device *device,
    159		int type, int value, char *data, int len)
    160{
    161	return usb_control_msg_send(device, 0, type,
    162				    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    163				    value, 0, data, len, 1000, GFP_KERNEL);
    164}
    165
    166static int usb6fire_fw_ezusb_read(struct usb_device *device,
    167		int type, int value, char *data, int len)
    168{
    169	return usb_control_msg_recv(device, 0, type,
    170				    USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    171				    value, 0, data, len, 1000, GFP_KERNEL);
    172}
    173
    174static int usb6fire_fw_fpga_write(struct usb_device *device,
    175		char *data, int len)
    176{
    177	int actual_len;
    178	int ret;
    179
    180	ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
    181			&actual_len, 1000);
    182	if (ret < 0)
    183		return ret;
    184	else if (actual_len != len)
    185		return -EIO;
    186	return 0;
    187}
    188
    189static int usb6fire_fw_ezusb_upload(
    190		struct usb_interface *intf, const char *fwname,
    191		unsigned int postaddr, u8 *postdata, unsigned int postlen)
    192{
    193	int ret;
    194	u8 data;
    195	struct usb_device *device = interface_to_usbdev(intf);
    196	const struct firmware *fw = NULL;
    197	struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
    198			GFP_KERNEL);
    199
    200	if (!rec)
    201		return -ENOMEM;
    202
    203	ret = request_firmware(&fw, fwname, &device->dev);
    204	if (ret < 0) {
    205		kfree(rec);
    206		dev_err(&intf->dev,
    207			"error requesting ezusb firmware %s.\n", fwname);
    208		return ret;
    209	}
    210	ret = usb6fire_fw_ihex_init(fw, rec);
    211	if (ret < 0) {
    212		kfree(rec);
    213		release_firmware(fw);
    214		dev_err(&intf->dev,
    215			"error validating ezusb firmware %s.\n", fwname);
    216		return ret;
    217	}
    218	/* upload firmware image */
    219	data = 0x01; /* stop ezusb cpu */
    220	ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
    221	if (ret) {
    222		kfree(rec);
    223		release_firmware(fw);
    224		dev_err(&intf->dev,
    225			"unable to upload ezusb firmware %s: begin message.\n",
    226			fwname);
    227		return ret;
    228	}
    229
    230	while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
    231		ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
    232				rec->data, rec->len);
    233		if (ret) {
    234			kfree(rec);
    235			release_firmware(fw);
    236			dev_err(&intf->dev,
    237				"unable to upload ezusb firmware %s: data urb.\n",
    238				fwname);
    239			return ret;
    240		}
    241	}
    242
    243	release_firmware(fw);
    244	kfree(rec);
    245	if (postdata) { /* write data after firmware has been uploaded */
    246		ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
    247				postdata, postlen);
    248		if (ret) {
    249			dev_err(&intf->dev,
    250				"unable to upload ezusb firmware %s: post urb.\n",
    251				fwname);
    252			return ret;
    253		}
    254	}
    255
    256	data = 0x00; /* resume ezusb cpu */
    257	ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
    258	if (ret) {
    259		dev_err(&intf->dev,
    260			"unable to upload ezusb firmware %s: end message.\n",
    261			fwname);
    262		return ret;
    263	}
    264	return 0;
    265}
    266
    267static int usb6fire_fw_fpga_upload(
    268		struct usb_interface *intf, const char *fwname)
    269{
    270	int ret;
    271	int i;
    272	struct usb_device *device = interface_to_usbdev(intf);
    273	u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
    274	const char *c;
    275	const char *end;
    276	const struct firmware *fw;
    277
    278	if (!buffer)
    279		return -ENOMEM;
    280
    281	ret = request_firmware(&fw, fwname, &device->dev);
    282	if (ret < 0) {
    283		dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
    284				fwname);
    285		kfree(buffer);
    286		return -EIO;
    287	}
    288
    289	c = fw->data;
    290	end = fw->data + fw->size;
    291
    292	ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
    293	if (ret) {
    294		kfree(buffer);
    295		release_firmware(fw);
    296		dev_err(&intf->dev,
    297			"unable to upload fpga firmware: begin urb.\n");
    298		return ret;
    299	}
    300
    301	while (c != end) {
    302		for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
    303			buffer[i] = bitrev8((u8)*c);
    304
    305		ret = usb6fire_fw_fpga_write(device, buffer, i);
    306		if (ret < 0) {
    307			release_firmware(fw);
    308			kfree(buffer);
    309			dev_err(&intf->dev,
    310				"unable to upload fpga firmware: fw urb.\n");
    311			return ret;
    312		}
    313	}
    314	release_firmware(fw);
    315	kfree(buffer);
    316
    317	ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
    318	if (ret) {
    319		dev_err(&intf->dev,
    320			"unable to upload fpga firmware: end urb.\n");
    321		return ret;
    322	}
    323	return 0;
    324}
    325
    326/* check, if the firmware version the devices has currently loaded
    327 * is known by this driver. 'version' needs to have 4 bytes version
    328 * info data. */
    329static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
    330{
    331	int i;
    332
    333	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
    334		if (!memcmp(version, known_fw_versions + i, 2))
    335			return 0;
    336
    337	dev_err(&intf->dev, "invalid firmware version in device: %4ph. "
    338			"please reconnect to power. if this failure "
    339			"still happens, check your firmware installation.",
    340			version);
    341	return -EINVAL;
    342}
    343
    344int usb6fire_fw_init(struct usb_interface *intf)
    345{
    346	int i;
    347	int ret;
    348	struct usb_device *device = interface_to_usbdev(intf);
    349	/* buffer: 8 receiving bytes from device and
    350	 * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
    351	u8 buffer[12];
    352
    353	ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
    354	if (ret) {
    355		dev_err(&intf->dev,
    356			"unable to receive device firmware state.\n");
    357		return ret;
    358	}
    359	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
    360		dev_err(&intf->dev,
    361			"unknown device firmware state received from device:");
    362		for (i = 0; i < 8; i++)
    363			printk(KERN_CONT "%02x ", buffer[i]);
    364		printk(KERN_CONT "\n");
    365		return -EIO;
    366	}
    367	/* do we need fpga loader ezusb firmware? */
    368	if (buffer[3] == 0x01) {
    369		ret = usb6fire_fw_ezusb_upload(intf,
    370				"6fire/dmx6firel2.ihx", 0, NULL, 0);
    371		if (ret < 0)
    372			return ret;
    373		return FW_NOT_READY;
    374	}
    375	/* do we need fpga firmware and application ezusb firmware? */
    376	else if (buffer[3] == 0x02) {
    377		ret = usb6fire_fw_check(intf, buffer + 4);
    378		if (ret < 0)
    379			return ret;
    380		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
    381		if (ret < 0)
    382			return ret;
    383		memcpy(buffer, ep_w_max_packet_size,
    384				sizeof(ep_w_max_packet_size));
    385		ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
    386				0x0003,	buffer, sizeof(ep_w_max_packet_size));
    387		if (ret < 0)
    388			return ret;
    389		return FW_NOT_READY;
    390	}
    391	/* all fw loaded? */
    392	else if (buffer[3] == 0x03)
    393		return usb6fire_fw_check(intf, buffer + 4);
    394	/* unknown data? */
    395	else {
    396		dev_err(&intf->dev,
    397			"unknown device firmware state received from device: ");
    398		for (i = 0; i < 8; i++)
    399			printk(KERN_CONT "%02x ", buffer[i]);
    400		printk(KERN_CONT "\n");
    401		return -EIO;
    402	}
    403	return 0;
    404}
    405