Example PCI Device

The example device is used for hardware calculation of the Adler-32 checksum. We provide it as a modified version of qemu. Driver for the example device: adlerdev.tar.gz

QEMU

To use the example device, a modified version of qemu is required, available in source version. To compile the modified version of qemu, you should:

  1. Clone the repository https://github.com/mwkmwkmwk/qemu

  2. git checkout adlerdev

  3. Make sure the dependencies are installed: ncurses, libsdl, curl, and in some distributions also ncurses-dev, libsdl-dev, curl-dev (package names may vary slightly depending on the distribution)

  4. Run ./configure with options as desired (see ./configure --help). The official binary was compiled with:

    --target-list=x86_64-softmmu
    
  5. Execute make

  6. Install by executing make install, or run directly (the binary is x86_64-softmmu/qemu-system-x86_64).

Device

The device is connected to the computer via the PCI bus -- the vendor identifier is 0x0666, and the device identifier is 0x0a32. The device has 5 registers:

BAR0 + 0x0000: INTR

Interrupt status register. When read, it has a value of 1 if the device is signaling an interrupt, or 0 if it is not. To respond to an interrupt (and cause the device to stop signaling an interrupt), you should write 1 to this register. You should also write 1 to this register when starting the device (the device may signal an interrupt at startup).

BAR0 + 0x0004: INTR_ENABLE

Interrupt enable register, read and write. If it has a value of 1, the device is allowed to signal an interrupt. If it has a value of 0, the device will not signal a PCI interrupt (the interrupt will still be visible in the INTR register).

BAR0 + 0x0008: DATA_PTR

Pointer to the data to be processed, read and write. During data processing, the device will automatically increment this pointer.

BAR0 + 0x000c: DATA_SIZE

Size of the data to be processed, read and write. Writing a non-zero value to this register will immediately start data processing. During processing, the device will automatically decrement this register. When all data has been processed (and this register drops to zero), an interrupt will be signaled (INTR will have a value of 1).

BAR0 + 0x0010: SUM

Current sum. Before processing data, the initial value of the sum should be written here. As data is processed, the device updates the sum.

To process data, you should:

  • make sure that INTR is zeroed and INTR_ENABLE is enabled

  • write the initial value of the sum to SUM

  • write the data pointer to DATA_PTR

  • write the data size to DATA_SIZE

  • wait for an interrupt

  • clear the interrupt (write 1 to INTR)