├── README.md ├── src ├── Makefile ├── pciemem.c └── pciemem.h └── uflash ├── Makefile ├── README.md └── uflash.c /README.md: -------------------------------------------------------------------------------- 1 | # PCIemem 2 | Linux kernel module for driving an USB3380 board, exposing a `/dev/pciemem` 3 | device node on the analysis machine representing the physical memory of the 4 | machine under test. 5 | 6 | See also [PCIleech](https://github.com/ufrisk/pcileech) from Ulf Frisk. 7 | 8 | ## uflash 9 | 10 | uflash is a userland tool used to read or flash the EEPROM on a PCI connected USB 3380. 11 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | M=$(shell pwd) 2 | KDIR ?= /lib/modules/`uname -r`/build 3 | 4 | obj-m += pciemem.o 5 | 6 | ifdef DEBUG 7 | CFLAGS_pciemem.o += -DDEBUG 8 | endif 9 | 10 | all: 11 | make -C $(KDIR) M=$(M) modules 12 | -------------------------------------------------------------------------------- /src/pciemem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pciemem.h" 3 | 4 | /* © 2016-2017 ANSSI 5 | * Yves-Alexis Perez 6 | * 7 | * This kernel module is heavily based on Greg KH usb-skeleton.c USB module 8 | * 9 | * It should be used with an USB3380 based board, in order to access the 10 | * physical memory of a machine under test (T). This kernel module is to be loaded 11 | * on the analysis machine (A). The USB3380 board should be inserted on a PCI 12 | * slot on machine T, and a USB cable should be plugged between USB3380 and 13 | * machine A. 14 | * 15 | */ 16 | 17 | MODULE_LICENSE("GPL"); 18 | 19 | /* USB part */ 20 | 21 | static void plx_delete(struct kref *kref) 22 | { 23 | struct usb_plx *dev = to_plx_dev(kref); 24 | 25 | usb_put_dev(dev->udev); 26 | kfree(dev->bulk_in_buffer); 27 | kfree(dev->bulk_out_buffer); 28 | kfree(dev); 29 | } 30 | 31 | static int pciemem_open(struct inode *inode, struct file *file) 32 | { 33 | struct usb_plx *dev; 34 | struct usb_interface *interface; 35 | int subminor; 36 | int retval = 0; 37 | pr_debug("open pciemem\n"); 38 | 39 | subminor = iminor(inode); 40 | 41 | interface = usb_find_interface(&plx_driver, subminor); 42 | if (!interface) { 43 | pr_err("%s - error, can't find device for minor %d\n", 44 | __func__, subminor); 45 | retval = -ENODEV; 46 | goto exit; 47 | } 48 | 49 | dev = usb_get_intfdata(interface); 50 | if (!dev) { 51 | retval = -ENODEV; 52 | goto exit; 53 | } 54 | 55 | retval = usb_autopm_get_interface(interface); 56 | if (retval) 57 | goto exit; 58 | 59 | /* increment our usage count for the device */ 60 | kref_get(&dev->kref); 61 | 62 | /* save our object in the file's private structure */ 63 | file->private_data = dev; 64 | 65 | pr_debug("opened pciemem\n"); 66 | 67 | exit: 68 | return retval; 69 | } 70 | 71 | static int pciemem_release(struct inode *inode, struct file *file) 72 | { 73 | struct usb_plx *dev; 74 | 75 | dev = file->private_data; 76 | if (dev == NULL) 77 | return -ENODEV; 78 | 79 | /* allow the device to be autosuspended */ 80 | mutex_lock(&dev->io_mutex); 81 | if (dev->interface) 82 | usb_autopm_put_interface(dev->interface); 83 | mutex_unlock(&dev->io_mutex); 84 | 85 | /* decrement the count on our device */ 86 | kref_put(&dev->kref, plx_delete); 87 | 88 | pr_debug("released pciemem\n"); 89 | return 0; 90 | } 91 | 92 | static int pciemem_flush(struct file *file, fl_owner_t id) 93 | { 94 | struct usb_plx *dev; 95 | int res; 96 | 97 | dev = file->private_data; 98 | if (dev == NULL) 99 | return -ENODEV; 100 | 101 | /* wait for io to stop */ 102 | mutex_lock(&dev->io_mutex); 103 | plx_draw_down(dev); 104 | 105 | /* read out errors, leave subsequent opens a clean slate */ 106 | spin_lock_irq(&dev->err_lock); 107 | res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0; 108 | dev->errors = 0; 109 | spin_unlock_irq(&dev->err_lock); 110 | 111 | mutex_unlock(&dev->io_mutex); 112 | 113 | return res; 114 | } 115 | 116 | static int plx_readreg(struct usb_plx *dev, u16 reg) 117 | { 118 | int ret = -EINVAL; 119 | u32 csrctl = 0U; // Format p362 120 | u32 *buf; 121 | int tlen = 0; 122 | int pipe; 123 | 124 | csrctl |= 0b01 << 4; // select USB configuration registers 125 | csrctl |= 1 << 6; // CSR Start 126 | csrctl |= 1 << 7; // CSR Read transaction 127 | csrctl |= (uint32_t ) reg << 16; // destination address 128 | 129 | buf = kmalloc(4, GFP_KERNEL); 130 | if (!buf) { 131 | pr_err("Can't allocate memory for USB buffer"); 132 | return -ENOMEM; 133 | } 134 | memcpy(buf, &csrctl, 4); 135 | 136 | pipe = usb_sndbulkpipe(dev->udev, dev->csr_out_endpointAddr); 137 | ret = usb_bulk_msg(dev->udev, pipe, buf, 4, &tlen, 1000); 138 | 139 | if (ret != 0 || tlen != 4) { 140 | pr_warn("Read reg USB out transfer failed: ret = %d, tlen = %d\n", ret, tlen); 141 | return ret; 142 | } 143 | 144 | memset(buf, 0, 4); 145 | ret = usb_bulk_msg(dev->udev, 146 | usb_rcvbulkpipe(dev->udev, dev->csr_in_endpointAddr), 147 | buf, 4, &tlen, 1000); 148 | if (ret != 0 || tlen != 4) 149 | pr_warn("USB in transfer failed: ret = %d, tlen = %d\n", ret, tlen); 150 | 151 | memcpy(&ret, buf, 4); 152 | return ret; 153 | } 154 | 155 | static int plx_writereg(struct usb_plx *dev, u16 reg, u32 data) 156 | { 157 | int ret = -EINVAL; 158 | u32 csrctl = 0U; // Format p362 159 | u32 *buf; 160 | int tlen = 0; 161 | unsigned int pipe; 162 | 163 | pr_debug("reg=0x%x, data=0x%.8x\n",reg, data); 164 | 165 | csrctl |= 0b1111; // CSR Bytes enable (all bytes) 166 | csrctl |= 0b01 << 4; // select USB configuration registers 167 | csrctl |= 1 << 6; // CSR Start 168 | csrctl |= 0 << 7; // CSR write transaction 169 | csrctl |= (uint32_t ) reg << 16; // destination address 170 | 171 | buf = kmalloc(8, GFP_KERNEL); 172 | if (!buf) { 173 | pr_err("Can't allocate memory for USB buffer"); 174 | return -ENOMEM; 175 | } 176 | memcpy(buf, &csrctl, 4); 177 | memcpy(buf+4, &data, 4); 178 | 179 | pipe = usb_sndbulkpipe(dev->udev, dev->csr_out_endpointAddr); 180 | ret = usb_bulk_msg(dev->udev, pipe, buf, 8, &tlen, 1000); 181 | 182 | if (ret != 0 || tlen != 8) 183 | pr_warn("USB out transfer failed: ret = %d, tlen = %d\n", ret, tlen); 184 | 185 | return ret; 186 | } 187 | // 188 | // read memory from addr to the buffer provided by caller using DMA 189 | // engine 190 | static int dma_readbuf(struct usb_plx *dev, const uint32_t dmaaddr, unsigned char* buf, size_t count) 191 | { 192 | int ret = -EINVAL; 193 | u32 dmacount = 0; 194 | u32 dmactl = dmactl_default; 195 | u32 dmastat = 0; 196 | int tlen = 0; 197 | u32 tmp = 0; 198 | u32 ep_avail = 0; 199 | int pipe; 200 | 201 | pr_debug("dev=%p, dmaaddr = 0x%.8x, buf=%p, count=%zu\n", dev, dmaaddr, buf, count); 202 | 203 | // Configure DMA registers 204 | plx_writereg(dev, REG_DMA1_CTL, dmactl); // start fresh 205 | plx_writereg(dev, REG_GPEP1_STAT, BIT(USB_STALL_SENT)); 206 | plx_writereg(dev, REG_GPEP1_STAT, BIT(FIFO_FLUSH) | BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)); 207 | 208 | plx_writereg(dev, REG_DMA1_ADDR, dmaaddr); 209 | 210 | //readreg(dev, REG_DMA1_COUNT, &dmacount); 211 | dmacount |= count; 212 | dmacount |= BIT(DMA_DIRECTION); // DMA Direction: IN (read) 213 | dmacount |= BIT(END_OF_CHAIN); 214 | dmacount |= BIT(VALID_BIT); 215 | dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE); 216 | plx_writereg(dev, REG_DMA1_COUNT, dmacount); 217 | 218 | dmactl = plx_readreg(dev, REG_DMA1_CTL); 219 | dmactl |= BIT(DMA_ENABLE); // DMA Enable 220 | dmactl |= BIT(DMA_FIFO_VALIDATE); // Validate last short packet 221 | plx_writereg(dev, REG_DMA1_CTL, dmactl); 222 | 223 | // Start DMA transfer 224 | dmastat = plx_readreg(dev, REG_DMA1_STAT); 225 | dmastat |= BIT(DMA_START); 226 | plx_writereg(dev, REG_DMA1_STAT, dmastat); 227 | 228 | while((dmacount & 0x7fffff) && ep_avail) { 229 | udelay(1000); 230 | tmp = plx_readreg(dev, REG_DMA1_COUNT); 231 | if(tmp != dmacount) 232 | { 233 | dmacount = tmp; 234 | pr_debug("dmacount=0x%.8x", dmacount); 235 | } 236 | 237 | ep_avail = plx_readreg(dev, REG_GPEP1_AVAIL); 238 | if(!ep_avail) 239 | pr_warn("USB IN FIFO full"); 240 | } 241 | 242 | pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr); 243 | ret = usb_bulk_msg(dev->udev, pipe, buf, count, &tlen, 1000); 244 | 245 | if (ret != 0 || tlen != count) 246 | { 247 | pr_warn("DMA in transfer failed (ret=%d, tlen=%d, dmaaddr=0x%x)", ret, tlen, dmaaddr); 248 | 249 | //readreg(dev, REG_GPEP1_RSP, &tmp); 250 | //if (tmp & BIT(CLEAR_ENDPOINT_TOGGLE)) 251 | 252 | //readreg(dev, REG_GPEP1_STAT, &tmp); 253 | //if (tmp & BIT(USB_STALL_SENT)) 254 | plx_writereg(dev, REG_GPEP1_STAT, BIT(USB_STALL_SENT)); 255 | plx_writereg(dev, REG_GPEP1_STAT, BIT(FIFO_FLUSH) | BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)); 256 | plx_writereg(dev, REG_GPEP1_RSP, BIT(CLEAR_ENDPOINT_TOGGLE)); 257 | } 258 | 259 | return ret; 260 | } 261 | // write memory to addr from the buffer provided by caller using DMA engine 262 | static int dma_writebuf(struct usb_plx *dev, const uint32_t dmaaddr, unsigned char* buf, size_t count) 263 | { 264 | int ret = -EINVAL; 265 | u32 dmacount = 0; 266 | u32 dmactl = dmactl_default; 267 | u32 dmastat = 0; 268 | int tlen = 0; 269 | int pipe; 270 | 271 | pr_debug("dev=%p, dmaaddr = 0x%.8x, buf=%p, count=%zu\n", dev, dmaaddr, buf, count); 272 | 273 | // Configure DMA registers 274 | plx_writereg(dev, REG_DMA0_CTL, dmactl); // start fresh 275 | plx_writereg(dev, REG_GPEP0_STAT, BIT(USB_STALL_SENT)); 276 | plx_writereg(dev, REG_GPEP0_STAT, BIT(FIFO_FLUSH) | BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)); 277 | 278 | plx_writereg(dev, REG_DMA0_ADDR, dmaaddr); 279 | 280 | //readreg(dev, REG_DMA0_COUNT, &dmacount); 281 | dmacount |= count; 282 | //dmacount |= BIT(DMA_DIRECTION); // DMA Direction: OUT (write) 283 | dmacount |= BIT(END_OF_CHAIN); 284 | dmacount |= BIT(VALID_BIT); 285 | dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE); 286 | plx_writereg(dev, REG_DMA0_COUNT, dmacount); 287 | 288 | dmactl = plx_readreg(dev, REG_DMA1_CTL); 289 | dmactl |= BIT(DMA_ENABLE); // DMA Enable 290 | dmactl |= BIT(DMA_FIFO_VALIDATE); // Validate last short packet 291 | plx_writereg(dev, REG_DMA0_CTL, dmactl); 292 | 293 | // Start DMA transfer 294 | dmastat = plx_readreg(dev, REG_DMA0_STAT); 295 | dmastat |= BIT(DMA_START); 296 | plx_writereg(dev, REG_DMA0_STAT, dmastat); 297 | 298 | #if 0 299 | while((dmacount & 0x7fffff) && ep_avail) { 300 | udelay(1000); 301 | tmp = plx_readreg(dev, REG_DMA0_COUNT); 302 | if(tmp != dmacount) 303 | { 304 | dmacount = tmp; 305 | pr_debug("dmacount=0x%.8x", dmacount); 306 | } 307 | 308 | ep_avail = plx_readreg(dev, REG_GPEP0_AVAIL); 309 | if(!ep_avail) 310 | pr_warn("USB IN FIFO full"); 311 | } 312 | #endif 313 | 314 | pipe = usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr); 315 | ret = usb_bulk_msg(dev->udev, pipe, buf, count, &tlen, 1000); 316 | 317 | if (ret != 0 || tlen != count) 318 | { 319 | pr_warn("DMA out transfer failed (ret=%d, tlen=%d, dmaaddr=0x%x)", ret, tlen, dmaaddr); 320 | 321 | //readreg(dev, REG_GPEP1_RSP, &tmp); 322 | //if (tmp & BIT(CLEAR_ENDPOINT_TOGGLE)) 323 | 324 | //readreg(dev, REG_GPEP1_STAT, &tmp); 325 | //if (tmp & BIT(USB_STALL_SENT)) 326 | plx_writereg(dev, REG_GPEP0_STAT, BIT(USB_STALL_SENT)); 327 | plx_writereg(dev, REG_GPEP0_STAT, BIT(FIFO_FLUSH) | BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)); 328 | plx_writereg(dev, REG_GPEP0_RSP, BIT(CLEAR_ENDPOINT_TOGGLE)); 329 | } 330 | 331 | return ret; 332 | } 333 | 334 | static ssize_t pciemem_read(struct file *file, char *buffer, size_t count, 335 | loff_t *ppos) 336 | { 337 | struct usb_plx *dev; 338 | int rv; 339 | 340 | if (count > DMA_BUFLEN) 341 | return -EINVAL; 342 | 343 | dev = file->private_data; 344 | pr_debug("dev=%p, ppos=%p, *ppos=%llx\n", dev, ppos, *ppos); 345 | rv = dma_readbuf(dev, *ppos, dev->bulk_in_buffer, count); 346 | pr_debug("dma_readbuf: rv=%d\n", rv); 347 | if (rv < 0) 348 | return rv; 349 | //print_hex_dump(KERN_DEBUG, "buf: ", DUMP_PREFIX_OFFSET, 16, 1, dev->bulk_in_buffer, count, true); 350 | if (copy_to_user(buffer, dev->bulk_in_buffer, count)) 351 | rv = -EFAULT; 352 | else 353 | { 354 | rv = count; 355 | *ppos += count; 356 | } 357 | return rv; 358 | } 359 | 360 | static ssize_t pciemem_write(struct file *file, const char *user_buffer, 361 | size_t count, loff_t *ppos) 362 | { 363 | struct usb_plx *dev; 364 | int rv = 0; 365 | 366 | /* verify that we actually have some data to write */ 367 | if (count == 0 || count > DMA_BUFLEN) 368 | return -EINVAL; 369 | 370 | dev = file->private_data; 371 | pr_debug("dev=%p, ppos=%p, *ppos=%llx\n", dev, ppos, *ppos); 372 | if (copy_from_user(dev->bulk_out_buffer, user_buffer, count)) 373 | rv = -EFAULT; 374 | print_hex_dump(KERN_DEBUG, "buf: ", DUMP_PREFIX_OFFSET, 16, 1, dev->bulk_out_buffer, count, true); 375 | rv = dma_writebuf(dev, *ppos, dev->bulk_out_buffer, count); 376 | pr_debug("dma_writebuf: rv=%d\n", rv); 377 | if (rv < 0) 378 | return rv; 379 | else 380 | { 381 | rv = count; 382 | *ppos += count; 383 | } 384 | return rv; 385 | } 386 | 387 | static int plx_probe(struct usb_interface *interface, 388 | const struct usb_device_id *id) 389 | { 390 | struct usb_plx *dev; 391 | struct usb_host_interface *iface_desc; 392 | struct usb_endpoint_descriptor *endpoint; 393 | size_t buffer_size; 394 | int i; 395 | int retval = -ENOMEM; 396 | 397 | /* allocate memory for our device state and initialize it */ 398 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); 399 | if (!dev) { 400 | dev_err(&interface->dev, "Out of memory\n"); 401 | goto error; 402 | } 403 | kref_init(&dev->kref); 404 | sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); 405 | mutex_init(&dev->io_mutex); 406 | spin_lock_init(&dev->err_lock); 407 | init_usb_anchor(&dev->submitted); 408 | init_waitqueue_head(&dev->bulk_in_wait); 409 | 410 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); 411 | dev->interface = interface; 412 | 413 | /* set up the endpoint information */ 414 | /* use only the first bulk-in and bulk-out endpoints */ 415 | iface_desc = interface->cur_altsetting; 416 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 417 | endpoint = &iface_desc->endpoint[i].desc; 418 | 419 | if (!dev->bulk_in_endpointAddr && 420 | usb_endpoint_is_bulk_in(endpoint) && 421 | endpoint->bEndpointAddress & PLX_DMA_ENDPOINT) { 422 | /* we found the DMA bulk in endpoint */ 423 | buffer_size = usb_endpoint_maxp(endpoint); 424 | dev->bulk_in_size = buffer_size; 425 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; 426 | dev->bulk_in_buffer = kzalloc(DMA_BUFLEN, GFP_KERNEL); 427 | if (!dev->bulk_in_buffer) { 428 | dev_err(&interface->dev, 429 | "Could not allocate bulk_in_buffer\n"); 430 | goto error; 431 | } 432 | } 433 | if (!dev->bulk_out_endpointAddr && 434 | usb_endpoint_is_bulk_out(endpoint) && 435 | endpoint->bEndpointAddress & PLX_DMA_ENDPOINT) { 436 | /* we found the DMA bulk out endpoint */ 437 | buffer_size = usb_endpoint_maxp(endpoint); 438 | dev->bulk_out_size = buffer_size; 439 | dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 440 | dev->bulk_out_buffer = kzalloc(DMA_BUFLEN, GFP_KERNEL); 441 | if (!dev->bulk_out_buffer) { 442 | dev_err(&interface->dev, 443 | "Could not allocate bulk_out_buffer\n"); 444 | goto error; 445 | } 446 | } 447 | 448 | if (!dev->csr_in_endpointAddr && 449 | usb_endpoint_is_bulk_in(endpoint) && 450 | endpoint->bEndpointAddress & PLX_CSR_ENDPOINT) { 451 | /* we found the CSR bulk in endpoint */ 452 | dev->csr_in_endpointAddr = endpoint->bEndpointAddress; 453 | } 454 | if (!dev->csr_out_endpointAddr && 455 | usb_endpoint_is_bulk_out(endpoint) && 456 | endpoint->bEndpointAddress & PLX_CSR_ENDPOINT) { 457 | /* we found the CSR bulk out endpoint */ 458 | dev->csr_out_endpointAddr = endpoint->bEndpointAddress; 459 | } 460 | 461 | } 462 | if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { 463 | dev_err(&interface->dev, 464 | "Could not find both bulk-in and bulk-out endpoints\n"); 465 | goto error; 466 | } 467 | pr_debug("DMA endpoints: 0x%x/0x%x\n", 468 | dev->bulk_in_endpointAddr, 469 | dev->bulk_out_endpointAddr); 470 | pr_debug("CSR endpoints: 0x%x/0x%x\n", 471 | dev->csr_in_endpointAddr, 472 | dev->csr_out_endpointAddr); 473 | 474 | /* save our data pointer in this interface device */ 475 | usb_set_intfdata(interface, dev); 476 | 477 | /* we can register the device now, as it is ready */ 478 | retval = usb_register_dev(interface, &plx_class); 479 | if (retval) { 480 | /* something prevented us from registering this driver */ 481 | dev_err(&interface->dev, 482 | "Not able to get a minor for this device.\n"); 483 | usb_set_intfdata(interface, NULL); 484 | goto error; 485 | } 486 | 487 | /* let the user know what node this device is now attached to */ 488 | dev_info(&interface->dev, 489 | "PLX device now attached to /dev/pciemem%d", 490 | interface->minor); 491 | return 0; 492 | 493 | error: 494 | if (dev) 495 | /* this frees allocated memory */ 496 | kref_put(&dev->kref, plx_delete); 497 | return retval; 498 | } 499 | 500 | static void plx_disconnect(struct usb_interface *interface) 501 | { 502 | struct usb_plx *dev; 503 | int minor = interface->minor; 504 | 505 | dev = usb_get_intfdata(interface); 506 | usb_set_intfdata(interface, NULL); 507 | 508 | /* give back our minor */ 509 | usb_deregister_dev(interface, &plx_class); 510 | 511 | /* prevent more I/O from starting */ 512 | mutex_lock(&dev->io_mutex); 513 | dev->interface = NULL; 514 | mutex_unlock(&dev->io_mutex); 515 | 516 | usb_kill_anchored_urbs(&dev->submitted); 517 | 518 | /* decrement our usage count */ 519 | kref_put(&dev->kref, plx_delete); 520 | 521 | dev_info(&interface->dev, "pciemem #%d now disconnected", minor); 522 | } 523 | 524 | static void plx_draw_down(struct usb_plx *dev) 525 | { 526 | int time; 527 | 528 | time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); 529 | if (!time) 530 | usb_kill_anchored_urbs(&dev->submitted); 531 | } 532 | 533 | static int plx_suspend(struct usb_interface *intf, pm_message_t message) 534 | { 535 | struct usb_plx *dev = usb_get_intfdata(intf); 536 | 537 | if (!dev) 538 | return 0; 539 | plx_draw_down(dev); 540 | return 0; 541 | } 542 | 543 | static int skel_resume(struct usb_interface *intf) 544 | { 545 | return 0; 546 | } 547 | 548 | static int skel_pre_reset(struct usb_interface *intf) 549 | { 550 | struct usb_plx *dev = usb_get_intfdata(intf); 551 | 552 | mutex_lock(&dev->io_mutex); 553 | plx_draw_down(dev); 554 | 555 | return 0; 556 | } 557 | 558 | static int plx_post_reset(struct usb_interface *intf) 559 | { 560 | struct usb_plx *dev = usb_get_intfdata(intf); 561 | 562 | /* we are sure no URBs are active - no locking needed */ 563 | dev->errors = -EPIPE; 564 | mutex_unlock(&dev->io_mutex); 565 | 566 | return 0; 567 | } 568 | 569 | 570 | 571 | module_usb_driver(plx_driver); 572 | 573 | MODULE_LICENSE("GPL"); 574 | 575 | -------------------------------------------------------------------------------- /src/pciemem.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define PLX_VENDOR_ID 0x0525 9 | #define PLX_PRODUCT_ID 0x3380 10 | #define PLX_DEVICE_NAME "pciemem" 11 | 12 | /* USB part */ 13 | #define PLX_PCI_ENDPOINT 0xe 14 | #define PLX_CSR_ENDPOINT 0xd 15 | #define PLX_DMA_ENDPOINT 0x2 16 | 17 | /* General Purpose Endpoint registers */ 18 | #define REG_GPEP0_CFG 0x320 19 | #define REG_GPEP0_RSP 0x324 // CHECK! 20 | #define REG_GPEP0_STAT 0x32c 21 | #define REG_GPEP0_AVAIL 0x330 22 | #define REG_GPEP1_CFG 0x340 23 | #define REG_GPEP1_RSP 0x344 24 | #define REG_GPEP1_STAT 0x40c 25 | #define REG_GPEP1_AVAIL 0x410 26 | 27 | /* DMA registers */ 28 | #define REG_DMA0_CTL 0x180 29 | #define REG_DMA0_STAT 0x184 30 | #define REG_DMA0_COUNT 0x190 31 | #define REG_DMA0_ADDR 0x194 32 | 33 | #define REG_DMA1_CTL 0x1A0 34 | #define REG_DMA1_STAT 0x1A4 35 | #define REG_DMA1_COUNT 0x1B0 36 | #define REG_DMA1_ADDR 0x1B4 37 | 38 | static const u32 dmactl_default = 39 | (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) 40 | | (1 << DMA_CLEAR_COUNT_ENABLE) 41 | /* erratum 0116 workaround part 1 (use POLLING) */ 42 | | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) 43 | | (1 << DMA_VALID_BIT_POLLING_ENABLE) 44 | | (1 << DMA_VALID_BIT_ENABLE) 45 | //| (1 << DMA_SCATTER_GATHER_ENABLE) 46 | /* erratum 0116 workaround part 2 (no AUTOSTART) */ 47 | | (1 << DMA_ENABLE); 48 | 49 | /* Get a minor range for your devices from the usb maintainer */ 50 | #define USB_PLX_MINOR_BASE 192 51 | #define WRITES_IN_FLIGHT 8 52 | 53 | #define MAX_TRANSFER (PAGE_SIZE - 512) 54 | /* MAX_TRANSFER is chosen so that the VM is not stressed by 55 | allocations > PAGE_SIZE and the number of packets in a page 56 | is an integer 512 is the largest possible packet on EHCI */ 57 | 58 | #define DMA_BUFLEN 4 * 1024 * 1024 59 | static int plx_probe(struct usb_interface *interface, const struct usb_device_id *id); 60 | static void plx_disconnect(struct usb_interface *interface); 61 | static int plx_suspend(struct usb_interface *intf, pm_message_t message); 62 | static int plx_post_reset(struct usb_interface *intf); 63 | 64 | /* direct copy from usb-skeleton.c */ 65 | static int skel_resume(struct usb_interface *intf); 66 | static int skel_pre_reset(struct usb_interface *intf); 67 | 68 | static struct usb_device_id plx_table [] = { 69 | { USB_DEVICE(PLX_VENDOR_ID, PLX_PRODUCT_ID) }, 70 | { } 71 | }; 72 | static struct usb_driver plx_driver = { 73 | .name = PLX_DEVICE_NAME, 74 | .id_table = plx_table, 75 | .probe = plx_probe, 76 | .disconnect = plx_disconnect, 77 | .suspend = plx_suspend, 78 | .resume = skel_resume, 79 | .pre_reset = skel_pre_reset, 80 | .post_reset = plx_post_reset, 81 | .supports_autosuspend = 1, 82 | }; 83 | 84 | static ssize_t pciemem_read(struct file *, char *, size_t, loff_t *); 85 | static ssize_t pciemem_write(struct file *, const char *, size_t, loff_t *); 86 | static int pciemem_open(struct inode *, struct file *); 87 | static int pciemem_release(struct inode *, struct file *); 88 | static int pciemem_flush(struct file *file, fl_owner_t id); 89 | 90 | static struct file_operations fops = { 91 | .owner = THIS_MODULE, 92 | .read = pciemem_read, 93 | .write = pciemem_write, 94 | .open = pciemem_open, 95 | .release = pciemem_release, 96 | .flush = pciemem_flush, 97 | .llseek = generic_file_llseek, 98 | }; 99 | 100 | static struct usb_class_driver plx_class = { 101 | .name = PLX_DEVICE_NAME"%d", 102 | .fops = &fops, 103 | .minor_base = USB_PLX_MINOR_BASE, 104 | }; 105 | 106 | struct usb_plx { 107 | struct usb_device *udev; /* the usb device for this device */ 108 | struct usb_interface *interface; /* the interface for this device */ 109 | struct semaphore limit_sem; /* limiting the number of writes in progress */ 110 | struct usb_anchor submitted; /* in case we need to retract our submissions */ 111 | unsigned char *bulk_in_buffer; /* the buffer to receive data */ 112 | size_t bulk_in_size; /* the size of the receive buffer */ 113 | size_t bulk_in_filled; /* number of bytes in the buffer */ 114 | size_t bulk_in_copied; /* already copied to user space */ 115 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 116 | unsigned char *bulk_out_buffer; /* the buffer to transmit data */ 117 | size_t bulk_out_size; /* the size of the receive buffer */ 118 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 119 | __u8 csr_in_endpointAddr; /* the address of the CSR in endpoint */ 120 | __u8 csr_out_endpointAddr; /* the address of the CSR out endpoint */ 121 | int errors; /* the last request tanked */ 122 | bool ongoing_read; /* a read is going on */ 123 | spinlock_t err_lock; /* lock for errors */ 124 | struct kref kref; 125 | struct mutex io_mutex; /* synchronize I/O with disconnect */ 126 | wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ 127 | }; 128 | 129 | static void plx_draw_down(struct usb_plx *dev); 130 | 131 | static int plx_readreg(struct usb_plx *dev, u16 reg); 132 | #define to_plx_dev(d) container_of(d, struct usb_plx, kref) 133 | -------------------------------------------------------------------------------- /uflash/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS +=-O2 -W -Wall -std=gnu99 -pedantic 2 | CFLAGS += -fPIE -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security 3 | ifdef DEBUG 4 | CFLAGS += -g -ggdb -O0 5 | endif 6 | 7 | CPPFLAGS += -D_FORTIFY_SOURCE=2 8 | 9 | LDFLAGS += -lpci 10 | LDFLAGS += -fPIE -pie -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,-O1 -Wl,-z,defs 11 | 12 | all: uflash 13 | 14 | clean: 15 | -rm uflash 16 | -------------------------------------------------------------------------------- /uflash/README.md: -------------------------------------------------------------------------------- 1 | # uflash 2 | 3 | uflash is a userland utility to dump and flash the content of an USB3380 board 4 | EEPROM, which contains the configuration for the USB3380 chip. 5 | 6 | The EEPROM is accessed through registers mapped to the PCI configuration space, 7 | so the USB3380 board needs to be plugged on a PCIe slot of the analysis machine, 8 | and not on a USB port, like when using PCIemem or PCIleech. 9 | 10 | `uflash` has two commands: 11 | 12 | - `dump` to read the EEPROM content and write it to a local `file` 13 | - `flash` for writing the EEPROM using a local `file` 14 | -------------------------------------------------------------------------------- /uflash/uflash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* Read/write an USB 3380 EEPROM 13 | * © 2016-2017 ANSSI 14 | * 15 | * Yves-Alexis Perez 16 | * 17 | * Permission is hereby granted, free of charge, to any person obtaining a copy 18 | * of this software and associated documentation files (the "Software"), to deal 19 | * in the Software without restriction, including without limitation the rights 20 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | * copies of the Software, and to permit persons to whom the Software is 22 | * furnished to do so, subject to the following conditions: 23 | * 24 | * The above copyright notice and this permission notice shall be included in all 25 | * copies or substantial portions of the Software. 26 | * 27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 | * SOFTWARE. 34 | * 35 | * Documentation from USB 3380-AA/AB Data Book, v1.3 -- 7/10/12 36 | * Chapter 5 Serial EEPROM Controller 37 | * Chapter 14 PCI Configuration registers 38 | * 14.14.3 Device specific registers - Serial EEPROM (Offsets 260h - 26Ch) 39 | */ 40 | 41 | #define OFFSET_REG_EEPROM_CTL 0x260 42 | #define OFFSET_REG_EEPROM_DATA 0x264 43 | #define DEVICE_WAIT_TIME 10*1000 44 | 45 | #define EEPROM_CMD 13 46 | #define EEPROM_RDY 24 47 | #define EEPROM_WEN 25 48 | 49 | #define EEPROM_HEADER_SIZE 4 /* Table 5-1 Serial EEPROM Data Format */ 50 | #define EEPROM_ADDR_WIDTH 2 /* ours always returns 0b00 (undefined) but it 51 | seems to use 2-bytes addressing */ 52 | 53 | #define SUBSYSTEM_VENDOR "0x10b5" 54 | #define SUBSYSTEM_DEVICE "0x3380" 55 | 56 | int check_subsystem(char* devpath) 57 | { 58 | char subpath[] = "/sys/bus/pci/devices/0000:00:00.0/subsystem_vendor"; 59 | int fd = -ENOENT; 60 | char info[] = SUBSYSTEM_VENDOR; 61 | 62 | /* check subsystem vendor id */ 63 | sprintf(subpath, "%s/subsystem_vendor", devpath); 64 | fd = open(subpath, O_RDONLY); 65 | if (fd < 0) 66 | return -ENODEV; 67 | 68 | if (read(fd, info, 7) < 7) 69 | return -ENODEV; 70 | 71 | close(fd); 72 | 73 | if (strncmp(info, SUBSYSTEM_VENDOR, 6)) 74 | return -ENODEV; 75 | 76 | /* check subsystem device id */ 77 | sprintf(subpath, "%s/subsystem_device", devpath); 78 | fd = open(subpath, O_RDONLY); 79 | if (fd < 0) 80 | return -ENODEV; 81 | 82 | if (read(fd, info, 7) < 7) 83 | return -ENODEV; 84 | 85 | close(fd); 86 | 87 | if (strncmp(info, SUBSYSTEM_DEVICE, 6)) 88 | return -ENODEV; 89 | 90 | return 0; 91 | } 92 | 93 | int open_config(char* devpath) 94 | { 95 | char res[] = "/sys/bus/pci/devices/0000:00:00.0/config"; 96 | 97 | sprintf(res, "%s/config", devpath); 98 | return open(res, O_RDWR); 99 | } 100 | 101 | int write_reg(const int config, const off_t reg, const uint32_t data) 102 | { 103 | return pwrite(config, &data, 4, reg); 104 | } 105 | 106 | int read_reg(int config, off_t reg, uint32_t *data) 107 | { 108 | return pread(config, data, 4, reg); 109 | } 110 | 111 | void eeprom_write_init(int config) 112 | { 113 | uint32_t eectl = 0; 114 | 115 | read_reg(config, OFFSET_REG_EEPROM_CTL, &eectl); 116 | /* only keep bits 23-16, serial EEPROM status */ 117 | eectl = (0x00ff0000 & eectl); 118 | /* set write latch enable, 0b110 */ 119 | eectl |= 6 << EEPROM_CMD; 120 | write_reg(config, OFFSET_REG_EEPROM_CTL, eectl); 121 | usleep(DEVICE_WAIT_TIME); 122 | } 123 | 124 | 125 | void eeprom_write_exit(int config) 126 | { 127 | uint32_t eectl = 0; 128 | 129 | read_reg(config, OFFSET_REG_EEPROM_CTL, &eectl); 130 | /* only keep bits 23-16, serial EEPROM status */ 131 | eectl = (0x00ff0000 & eectl); 132 | /* reset write latch enable, 0b100 */ 133 | eectl |= 4 << EEPROM_CMD; 134 | write_reg(config, OFFSET_REG_EEPROM_CTL, eectl); 135 | usleep(DEVICE_WAIT_TIME); 136 | } 137 | 138 | 139 | int eeprom_read_word(int config, off_t offset, uint32_t *data) 140 | { 141 | uint32_t eectl=0; 142 | int ret=0; 143 | 144 | /* get current data of the EEPROM CTL register */ 145 | ret = read_reg(config, OFFSET_REG_EEPROM_CTL, &eectl); 146 | 147 | /* only keep bits 23-16, serial EEPROM status */ 148 | eectl = (0x00ff0000 & eectl); 149 | eectl |= offset >> EEPROM_ADDR_WIDTH; 150 | eectl |= 3 << EEPROM_CMD; /* read 4 bytes to EEPROM_DATA register */ 151 | 152 | ret = write_reg(config, OFFSET_REG_EEPROM_CTL, eectl); 153 | usleep(DEVICE_WAIT_TIME); 154 | 155 | /* read data from the EEPROM data register */ 156 | ret = read_reg(config, OFFSET_REG_EEPROM_DATA, data); 157 | 158 | return ret; 159 | } 160 | int eeprom_write_word(int config, off_t offset, uint32_t data) 161 | { 162 | uint32_t eectl=0; 163 | int ret=-1; 164 | uint32_t check; 165 | 166 | eeprom_write_init(config); 167 | /* write data to the EEPROM data register */ 168 | ret = write_reg(config, OFFSET_REG_EEPROM_DATA, data); 169 | 170 | /* get current data of the EEPROM CTL register */ 171 | ret = read_reg(config, OFFSET_REG_EEPROM_CTL, &eectl); 172 | 173 | /* only keep bits 23-16, serial EEPROM status */ 174 | eectl = (0x00ff0000 & eectl); 175 | eectl |= offset >> EEPROM_ADDR_WIDTH; 176 | eectl |= 2 << EEPROM_CMD; /* write 4 bytes from EEPROM_DATA buffer */ 177 | eectl |= 1 << EEPROM_RDY; 178 | eectl |= 1 << EEPROM_WEN; 179 | 180 | write_reg(config, OFFSET_REG_EEPROM_CTL, eectl); 181 | usleep(DEVICE_WAIT_TIME); 182 | 183 | ret = eeprom_read_word(config, offset, &check); 184 | if (ret > 0 && check == data) return 0; 185 | 186 | error(0, 0, "ret=%d, offset=0x%.2lx, data=0x%.8x, check=0x%.8x", ret, offset, data, check); 187 | 188 | return ret; 189 | } 190 | 191 | int eeprom_write(int config, int file) 192 | { 193 | uint32_t data=0; 194 | ssize_t count=0; 195 | off_t offset=0; 196 | 197 | do 198 | { 199 | count = pread(file, &data, 4, offset); 200 | switch(count) 201 | { 202 | case 1: 203 | if (errno == EINTR) continue; 204 | 205 | error(0, errno, "pread()"); 206 | return -1; 207 | ;; 208 | case 0: /* EOF */ 209 | break; 210 | ;; 211 | case 4: 212 | if (eeprom_write_word(config, offset, data) < 0) return -1; 213 | offset += count; 214 | continue; 215 | ;; 216 | default: /* something wrong happened */ 217 | error(0, 0, "pread returned %ld\n", count); 218 | return -1; 219 | ;; 220 | } 221 | } while(count); 222 | 223 | return 0; 224 | } 225 | 226 | /* get EEPROM size, Table 5-1 and 5-2, pp 36-37 */ 227 | int eeprom_get_size(int config) 228 | { 229 | uint32_t data=0; 230 | int eep_size = EEPROM_HEADER_SIZE; 231 | 232 | eeprom_read_word(config, 0, &data); 233 | 234 | /* check signature */ 235 | if ((data & 0xff) != 0x5a) 236 | return -1; 237 | 238 | /* check format (0 for Configuration Register Load */ 239 | if (data & 0xff00) 240 | return -1; 241 | 242 | eep_size += (data & 0xffff0000) >> 16; 243 | return eep_size; 244 | } 245 | 246 | int eeprom_read(int config, int dst, ssize_t size) 247 | { 248 | int ret=-1; 249 | uint32_t data; 250 | 251 | for(off_t offset=0; offset < size; offset += 4) 252 | { 253 | eeprom_read_word(config, offset, &data); 254 | ret = pwrite(dst, &data, 4, offset); 255 | if(ret < 0) return ret; 256 | } 257 | 258 | return ret; 259 | } 260 | 261 | int main(int argc, char* argv[]) 262 | { 263 | int config; 264 | char* devpath; 265 | int ret=0; 266 | int eep_size; 267 | int file; 268 | 269 | if (argc < 4) 270 | error(EXIT_FAILURE, 0, "Usage: %s ", argv[0]); 271 | 272 | devpath = strdup(argv[1]); 273 | printf("Using device file %s\n", devpath); 274 | 275 | /* safety check */ 276 | if (check_subsystem(devpath)) 277 | error(EXIT_FAILURE, 0, "Subsystem info don't match (should be %s:%s)", 278 | SUBSYSTEM_VENDOR, SUBSYSTEM_DEVICE); 279 | 280 | if (geteuid() > 0) 281 | error(EXIT_FAILURE, 0, "You must be root.\n"); 282 | 283 | config = open_config(devpath); 284 | if (config == -1) 285 | error(EXIT_FAILURE, errno, "Can't open device %s PCI configuration header\n", devpath); 286 | 287 | if (strncmp(argv[2], "dump", 4) == 0) 288 | { 289 | eep_size = eeprom_get_size(config); 290 | 291 | if (eep_size < EEPROM_HEADER_SIZE) 292 | error(EXIT_FAILURE, 0, "Invalid EEPROM size (%d)", eep_size); 293 | 294 | file = open(argv[3], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 295 | if (file == -1) 296 | error(EXIT_FAILURE, errno, "Can't open file %s", argv[3]); 297 | 298 | return eeprom_read(config, file, eep_size); 299 | } 300 | 301 | if (strncmp(argv[2], "flash", 5) == 0) 302 | { 303 | eeprom_write_init(config); 304 | 305 | file = open(argv[3], O_RDONLY); 306 | if (file == -1) 307 | error(EXIT_FAILURE, errno, "Can't open file %s", argv[3]); 308 | 309 | return eeprom_write(config, file); 310 | } 311 | 312 | return ret; 313 | } 314 | --------------------------------------------------------------------------------