# opae.io # ## SYNOPSIS ## `opae.io ls [-v,--viddid VID:DID]`
`opae.io init [-d PCI_ADDR USER[:GROUP]]`
`opae.io release [-d PCI_ADDR]`
`opae.io [-d PCI_ADDR] [-r REGION] walk OFFSET [-u,--show-uuid]`
`opae.io [-d PCI_ADDR] [-r REGION] peek OFFSET`
`opae.io [-d PCI_ADDR] [-r REGION] poke OFFSET VALUE`
`opae.io [-d PCI_ADDR] [-r REGION] SCRIPT ARG1 ARG2 ... ARGN`
`opae.io [-d PCI_ADDR] [-r REGION]` ## DESCRIPTION ## ```opae.io``` is an interactive Python environment packaged on top of ```libopaevfio.so```, which provides user space access to PCIe devices via the vfio-pci driver. The main feature of opae.io is its built-in Python command interpreter, along with some Python bindings that provide a means to access Configuration and Status Registers (CSRs) that reside on the PCIe device. ```opae.io``` has two operating modes: command line mode and interactive mode. ## COMMAND LINE MODE ## To view the accelerator devices that are present on the system, ```opae.io``` provides the ```ls``` command option. `opae.io ls [-v,--viddid VID:DID]` Each accelerator device is listed along with the PCIe address, the PCIe vendor/device ID, a brief description of the device, and the driver to which the device is currently bound. ```opae.io``` provide an option to initialize a PCIe device for use with the vfio-pci driver. In order for the device CSRs to be accessed from user space, the device must first be bound to the vfio-pci driver. This is the job of the ```init``` command option. `opae.io init [-d PCI_ADDR USER:[GROUP]]` The ```init``` command unbinds the specified device from its current driver and binds it to vfio-pci. This creates a new vfio group under /dev/vfio. This group path is then used by the ```libopaevfio.so``` library to interact with the device. To release the PCIe device from vfio-pci and return it to use with its previous driver, the ```release``` command option is used. `opae.io release [-d PCI_ADDR]` The ```release``` command option reverses the actions of the last ```init``` command, releasing the device from vfio-pci and binding it to the driver which was bound at the time the ```init``` command was issued. The ```walk``` command option traverses and displays the Device Feature List of the given region. `opae.io walk [-d PCI_ADDR] [-r REGION] [OFFSET] [-u,--show-uuid]` The various fields of each Device Feature Header are displayed. The `--show-uuid` option additionally displays the GUID for each feature. OFFSET can be used to specify the beginning of the DFL in the MMIO region. The ```peek``` command option reads and displays a CSR value. `opae.io peek [-d PCI_ADDR] [-r REGION] OFFSET` The ```poke``` command option writes a given value to a CSR. `opae.io poke [-d PCI_ADDR] [-r REGION] OFFSET VALUE` ```opae.io``` can also execute Python scripts from the command line. These Python scripts may contain calls to the device built-in functions that are available during an interactive session. Refer to the description of interactive mode for details. `opae.io [-d PCI_ADDR] [-r REGION] myscript.py a b c` In order to enter the interactive mode of ```opae.io```, simply invoke it and optionally pass the desired device address and MMIO region options. `opae.io [-d PCI_ADDR] [-r REGION]` ## INTERACTIVE MODE ## Upon entering interactive mode, ```opae.io``` begins a Python interpreter session and displays the command prompt shown below: 0000:3f:00.0[0]>> The first portion of the prompt shows the address of the active PCIe device, here 0000:3f:00.0. The part in square brackets shows the active MMIO region, here [0]. The interpreter waits for a valid Python command, then attempts to execute the given command in the usual way. The only differences between the traditional Python command intepreter and ```opae.io``` are that opae.io provides 1) the notion of an active PCIe device and MMIO region and 2) several built-in functions and objects that allow manipulating the active device and MMIO region. ### BUILT-IN FUNCTIONS ### The ```opae.io``` built-in functions assume an active device and MMIO region. Attempting to use the built-in functions without first opening a device and region will result in errors. `peek(OFFSET)` The `peek` built-in function reads and displays a CSR value from the active device and region, at the offset supplied by its argument. 0000:3f:00.0[0]>> peek(0x28)
0xdeadbeef `poke(OFFSET, VALUE)` The `poke` built-in function writes the given VALUE to the current MMIO region at the given OFFSET. 0000:3f:00.0[0]>> poke(0x28, 0xdeadbeef) `read_csr(OFFSET)` The `read_csr` built-in function returns the value of the CSR at the active MMIO region and the given OFFSET. 0000:3f:00.0[0]>> print('0x{:0x}'.format(read_csr(0x28)))
0xdeadbeef `write_csr(OFFSET, VALUE)` The `write_csr` built-in function writes the given VALUE to the current MMIO region at the given OFFSET. 0000:3f:00.0[0]>> write_csr(0x28, 0xdeadbeef) `device(PCI_ADDR)` The `device` built-in function allows changing the active PCIe device. 0000:3f:00.0[0]>> device('0000:2b:00.0')
0000:2b:00.0>> `region(REGION)` The `region` built-in function allows changing the active MMIO region. 0000:2b:00.0>> region(0)
0000:2b:00.0[0]>> `allocate_buffer(SIZE)` The `allocate_buffer` built-in function creates and returns a DMA buffer object. The underlying buffer will be SIZE bytes in length. 0000:2b:00.0[0]>> b1 = allocate_buffer(4096)
0000:2b:00.0[0]>> print(b1.size, '0x{:0x}'.format(b1.address), b1.io_address)
4096 0x7f9361c66000 0 `version()` The `version` built-in function returns a tuple containing the four components used to identify the opae.io version: 0000:2b:00.0[0]>> print(version())
('opae.io', 0, 2, 0) ### BUILT-IN OBJECTS ### ```opae.io``` interactive mode provides two global objects corresponding to the current device and that device's current MMIO region. These objects are referred to by global variables `the_device` and `the_region`, respectively. The `device` class: the_device.descriptor() : method that returns the integer file descriptor of the `VFIO container`. 0000:2b:00.0[0]>> print(the_device.descriptor())
5 the_device.__repr__() : method that is invoked when a `device` object is printed. 0000:2b:00.0[0]>> print(the_device)
0000:2b:00.0 the_device.allocate(SIZE) : method that allocates and returns a `system_buffer` object. The buffer will be mapped into the DMA space of `the_device`. 0000:2b:00.0[0]>> b1 = the_device.allocate(4096) the_device.pci_address() : read-only property that returns the PCIe address of `the_device`. 0000:2b:00.0[0]>> print(the_device.pci_address)
0000:2b:00.0 the_device.num_regions : read-only property that returns the number of MMIO regions in `the_device`. 0000:2b:00.0[0]>> print(the_device.num_regions)
2 the_device.regions : read-only property that returns a list of the active MMIO regions of `the_device`: 0000:2b:00.0[0]>> print(the_device.regions)
[0, 2] The `region` class: the_region.write32(OFFSET, VALUE) : method that writes a 32-bit VALUE to the CSR at OFFSET. the_region.read32(OFFSET) : method that returns a 32-bit CSR at the given OFFSET. 0000:2b:00.0[0]>> the_region.write32(0x28, 0xdeadbeef)
0000:2b:00.0[0]>> print('0x{:0x}'.format(the_region.read32(0x28)))
0xdeadbeef the_region.write64(OFFSET, VALUE): method that writes a 64-bit VALUE to the CSR at OFFSET. the_region.read64(OFFSET): method that returns a 64-bit CSR at the given OFFSET. 0000:2b:00.0[0]>> the_region.write64(0x28, 0xbaddecaf)
0000:2b:00.0[0]>> print('0x{:0x}'.format(the_region.read64(0x28)))
0xbaddecaf the_region.index(): method that returns the MMIO index of `the_region`. 0000:2b:00.0[0]>> print(the_region.index())
0 the_region.__repr__(): method that is invoked when a `region` object is printed. 0000:2b:00.0[0]>> print(the_region)
0 the_region.__len__(): method that is invoked to determine the MMIO region size. 0000:2b:00.0[0]>> print(len(the_region))
524288 The `allocate_buffer()` built-in function and the `device.allocate()` method return objects of type `system_buffer`. The `system_buffer` class is as follows: `buf.size`: read-only property that gives the buffer size. 0000:2b:00.0[0]>> print(b1.size)
4096 `buf.address`: read-only property that gives the buffer's user mode virtual address. 0000:2b:00.0[0]>> print('0x{:0x}'.format(b1.address))
0x7f2c15d8200 `buf.io_address`: read-only property that gives the buffer's IO address. 0000:2b:00.0[0]>> print('0x{:0x}'.format(b1.io_address))
0x0 `buf.__getitem__` and `buf.__setitem__`: indexing get/set of 64-bit data item. 0000:2b:00.0[0]>> b1[0] = 0xdecafbad
0000:2b:00.0[0]>> print('0x{:0x}'.format(b1[0]))
0xdecafbad `buf.read8(OFFSET)`
`buf.read16(OFFSET)`
`buf.read32(OFFSET)`
`buf.read64(OFFSET)` : methods that read the given size data item from the given buffer OFFSET. `buf.fill8(VALUE)`
`buf.fill16(VALUE)`
`buf.fill32(VALUE)`
`buf.fill64(VALUE)` : methods that fill the buffer with the given VALUE, using the given size. `b1.compare(b2)`: method that compares buffers. The method returns the index of the first byte that miscompares, or the length of b1. ## Revision History ## Document Version | Intel Acceleration Stack Version | Changes -----------------|----------------------------------|-------- 2021.01.25 | IOFS EA | Initial release.