Project

General

Profile

Isochronous USB Issues ยป xhci-bw-override.c

tnt, 01/18/2023 03:08 PM

 
1
/*
2
 * xhci-bw-override.c
3
 *
4
 * Small utility that scans for xHCI controller, check if they're compatible
5
 * and overwrite the FS isochronous bandwidth limit register
6
 *
7
 * Copyright (C) 2022  Sylvain Munaut <tnt@246tNt.com>
8
 * SPDX-License-Identifier: GPL-3.0-or-later
9
 */
10

    
11
#include <dirent.h>
12
#include <inttypes.h>
13
#include <fcntl.h>
14
#include <stdio.h>
15
#include <stdint.h>
16
#include <string.h>
17
#include <unistd.h>
18

    
19
#include <sys/mman.h>
20

    
21

    
22
struct pci_dev {
23
	uint16_t vendor;
24
	uint16_t device;
25
	uint32_t class;
26
	char path[PATH_MAX];
27
};
28

    
29
typedef void (*pci_dev_cb_t)(struct pci_dev *dev);
30

    
31

    
32
static int
33
read_sysfs_hex(const char *filename, uint32_t *val)
34
{
35
	FILE *f = fopen(filename, "r");
36
	if (!f)
37
		return -1;
38
	if (fscanf(f, "0x%x\n", val) != 1)
39
		return -1;
40
	fclose(f);
41
	return 0;
42
}
43

    
44
static int
45
fill_pci_dev(struct pci_dev *dev, const char *path)
46
{
47
	char fname[512];
48
	uint32_t v;
49

    
50
	strncpy(dev->path, path, sizeof(fname));
51

    
52
	snprintf(fname, sizeof(fname), "%s/vendor", path);
53
	if (read_sysfs_hex(fname, &v))
54
		return -1;
55
	dev->vendor = v;
56

    
57
	snprintf(fname, sizeof(fname), "%s/device", path);
58
	if (read_sysfs_hex(fname, &v))
59
		return -1;
60
	dev->device = v;
61

    
62
	snprintf(fname, sizeof(fname), "%s/class", path);
63
	if (read_sysfs_hex(fname, &v))
64
		return -1;
65
	dev->class = v;
66

    
67
	return 0;
68
}
69

    
70
static void
71
scan_pci_devices(pci_dev_cb_t cb)
72
{
73
	DIR *dd_root, *dd_bus;
74
	struct dirent *de_root, *de_bus;
75
	char fname[PATH_MAX];
76

    
77
	dd_root = opendir("/sys/devices/");
78
	if (!dd_root) {
79
		fprintf(stderr, "[!] Failed to open '/sys/devices/'\n");
80
		perror("opendir");
81
		return;
82
	}
83

    
84
	while (1) {
85
		de_root = readdir(dd_root);
86
		if (!de_root)
87
			break;
88

    
89
		if (strncmp(de_root->d_name, "pci", 3))
90
			continue;
91

    
92
		snprintf(fname, sizeof(fname), "/sys/devices/%s", de_root->d_name);
93

    
94
		dd_bus = opendir(fname);
95
		if (!dd_bus) {
96
			fprintf(stderr, "[!] Failed to open '%s', skipping\n", fname);
97
			perror("opendir");
98
			continue;
99
		}
100

    
101
		while (1) {
102
			struct pci_dev dev;
103

    
104
			de_bus = readdir(dd_bus);
105
			if (!de_bus)
106
				break;
107

    
108
			if (de_bus->d_type != DT_DIR)
109
				continue;
110

    
111
			if ((de_bus->d_name[0] < '0') || (de_bus->d_name[1] > '9'))
112
				continue;
113

    
114
			snprintf(fname, sizeof(fname), "/sys/devices/%s/%s", de_root->d_name, de_bus->d_name);
115
			if (fill_pci_dev(&dev, fname)) {
116
				fprintf(stderr, "[w] Failed to read info about '%s', skipping\n", fname);
117
				continue;
118
			}
119

    
120
			cb(&dev);
121
		}
122

    
123
		closedir(dd_bus);
124
	}
125

    
126
	closedir(dd_root);
127
}
128

    
129
static int
130
patch_device(struct pci_dev *dev)
131
{
132
	char fname[PATH_MAX];
133
	int fd;
134
	void *mem;
135

    
136
	snprintf(fname, sizeof(fname), "%s/resource0", dev->path);
137
	fd = open(fname, O_RDWR);
138
	if (fd < 0) {
139
		fprintf(stderr, "[!] Failed to open resource '%s'\n", fname);
140
		perror("open");
141
		return -1;
142
	}
143

    
144
	mem = mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
145
	if (!mem) {
146
		fprintf(stderr, "[!] Failed to mmmap\n");
147
		perror("mmap");
148
		close(fd);
149
		return -1;
150
	}
151

    
152
	volatile uint64_t *HOST_CTRL_BW_MAX_REG = (uint64_t *)(mem + 0x8128);
153
	uint64_t v;
154

    
155
	v = *HOST_CTRL_BW_MAX_REG;
156

    
157
	printf("[.] Previous HOST_CTRL_BW_MAX_REG value: %016" PRIx64 "\n", v);
158

    
159
	v &= 0xfffffff000ffffff;
160
	v |= 0x00000005b0000000;	/* Patched value */
161
	// v |= 0x0000000505000000;	/* Default value */
162

    
163
	printf("[.] Updated  HOST_CTRL_BW_MAX_REG value: %016" PRIx64 "\n", v);
164

    
165
	*HOST_CTRL_BW_MAX_REG = v;
166

    
167
     	close(fd);
168

    
169
	return 0;
170
}
171

    
172
static void
173
scan_cb(struct pci_dev *dev)
174
{
175
	if ((dev->vendor != 0x8086) || (dev->class != 0x0c0330))
176
		return;
177

    
178
	fprintf(stderr, "[+] Found Intel xHCI controller at '%s'\n", dev->path);
179
	patch_device(dev);
180
}
181

    
182
int main(int argc, char *argv[])
183
{
184
	if (geteuid() != 0) {
185
		fprintf(stderr, "[!] Please run as root\n");
186
		return -1;
187
	}
188

    
189
	if (argc == 1) {
190
		/* No arguments, scan all */
191
		scan_pci_devices(scan_cb);
192
	} else {
193
		struct pci_dev dev;
194

    
195
		if (fill_pci_dev(&dev, argv[1])) {
196
			fprintf(stderr, "[!] Failed to read info about '%s'\n", argv[1]);
197
			return -1;
198
		}
199

    
200
		if ((dev.vendor != 0x8086) || (dev.class != 0x0c0330)) {
201
			fprintf(stderr, "[!] Not an intel xHCI controller\n");
202
			return -1;
203
		}
204

    
205
		patch_device(&dev);
206
	}
207
}
    (1-1/1)
    Add picture from clipboard (Maximum size: 48.8 MB)