How do WINDOWS func kernel drivers communicate with actual hardware? - windows

So I understand that a kernel driver sits on top of HW device and then to communicate with the device via user space you will need to talk to the kernel driver via CreateFile && Read && Write. I have seen the design of Window's kernel drivers and their sample codes whether it is a USB or PCI or...
Now what I want to understand is how does the kernel drive communicate with the hardware? Where is the driver code would we usually find the code responsible for reading/writing registers on a certain device? What does the driver need to communicate with the device? I was told it is the BAR0 value that maps the HW to the virtual memory area which means any address we want to access on a physical device would start at that address. Is that correct? what If I have BAR0 = 0xfc500000, do i have to find addresses of certain register on the device and then ad it as an offset?

Driver need to get HW Resources from the OS. in a PCI device example, you will get MMIO Address and the interrupt vector. the MMIO Address is a physical address the PCI Controller and the BIOS map the device too.
the driver gets this value in EvtPepareHardware callback (in KMDF) and then need to map it to kernel Virtual address using MmMapIoSpace().
once you get a kernel Virtual address theoretically it is a "pointer" to the HW memory space and you can access the registers as you wish.
but it is recommended to use the HAL macros to void caching and other issues to access that memory. e.g. READ_REGISTER_ULONG64
to find the address of a registers you the Hardware device spec
for more info read this "Reading and Writing to Device Registers"

Related

How Operation System obtain Hardware ID

I am recently read documentation about Windows-Driver-Model, one of a chapter of it says :
Before a driver is installed for a new device, the bus or hub driver to which the device is connected assigns a hardware identifier (ID) to the device.
But how ??
For example the OS want to communicate with a USB device.
How can it ( the os ) obtain the hardware-id of the device ?
Is there some kind of protocol to communicate with the hardware that works like :
The OS send a signal ( or USB formatted message ) with a body of such as "I want to know hardware-id"
The hardware must response to this message to OS with a body of such as "My hardware-id is xxx"
If there is a protocol like this, could you please told me the "standard" of such a protocol.
On most modern computers every USB hub is connected to one xHCI controller (https://wiki.osdev.org/EXtensible_Host_Controller_Interface). At boot the BIOS will build ACPI tables in RAM that the OS will look for in conventional positions. Once the OS finds these tables, it will look at every entry to determine what devices are plugged to the computer including xHCI controllers. As stated on osdev.org
All xHCI controllers will have a Class ID of 0x0C, a Sublcass ID of 0x03, and an Interface value of 0x30. The configuration space for this device will contain two Base Address Registers: BAR0 and BAR1. These two 32-bit address fields combine to create a single 64-bit address that points to the base address of the memory mapped registers for the controller.
The memory mapped register of the xHCI s are then used to send commands to the USB device including commands to get the device descriptor of the USB device. The document on https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf is the spec for the xHCI. So if you want to really understand how it works under the hood then this is a great place to look at.

Multiple devices on mdio bus

I have multiple devices on MDIO bus (one AR8035 PHY, and 6 DP83849IFVS dual PHYs). The bus is connected to AM335x SoC with linux 4.14.40. Davinchi_mdio scans bus and finds all devices and attaches driver I think for AR8035. How can I access this bus via mdio? I want to write stand-lone (not PHY driver) kernel module, that can simply access mdio bus? How can I do that? I wanted to do that with phy_write/phy_read but I can't get struct phy_device* from my kernel module. How can I get struct phy_device* from the name of the interface ("eth0"). Will it be safe in terms of locks/mutaxes?
If you already have an subsystem for MDIO controller, then I can think of implementing an UIO driver for MDIO interface, which deals with read and write.
UIO driver is safe when compared to the messy kernel driver and complete control will be with the user application which uses that UIO.
**
*Each UIO device is accessed through a device file and several sysfs attribute files. The device file will be called /dev/uio0 for the first device, and /dev/uio1, /dev/uio2 and so on for subsequent devices.
/dev/uioX is used to access the address space of the card. Just use mmap() to access registers or RAM locations of your card.
Interrupts are handled by reading from /dev/uioX. A blocking read() from /dev/uioX will return as soon as an interrupt occurs.*
**

how to get physical address of V4L2 DMA virtual address?

I have a typical V4L2 driver that I use configured for memory mapped IO method. This driver hands off a virtual address to my user space app. All of this is working fine.
I have another driver that expects as input a kernel physical address. I want to connect the output of the V4L2 driver to the input of this driver but it needs a physical address (this driver controls FPGA functionality).
My understanding is that the kernel routine: virt_to_phys() routine will NOT work with DMA allocated memory mapped addresses. Is this true? If so, how do I get the physical address from the DMA memory mapped V4L2 virtual address that was passed into user space?
I am just hacking up a proof of concept thing here so hard coding some addresses is not an issue. This is the sole application running on a dedicated embedded platform.
Thanks,
-Andres
This can be explained in 3 steps:
V4L2 application will call VIDIOC_REQBUF to allocate a buffer. If memory type is VB2_MEMORY_MMAP. V4l2 framework driver will allocate buffer and pack it as vb2_dc_buf structure type and store this structure pointer in planes[plane].mem_priv. This structure will have DMA physical address.
Application has to call VIDIOC_EXPBUF by passing planes[plane].mem_priv. Then v4l2 framework implements vb2_core_expbuf() where it invokes DMA specific APIs like vb2_dc_get_dmabuf() and dma_buf_fd() to get DMA buffer fd.
Application can export this (pass this fd) to 2nd driver where the 2nd driver will import fd and convert back to DMA physical address using DMA APIs

Redirecting DMA memory access

I'm wondering if it is possible to redirect memory reading requests of a DMA device to another address on the OS level without the DMA device being noticed.
Let's say my PCIe card can access all the memory on my PC by directly reading the physical addresses. Can the MMU of the operating system redirect these requests to other addresses in
memory? That means the DMA address thinks it reads the correct physical addresses, but actually it is reading some other addresses?
Is that possible?

Map physical memory address to a user space application in windows

Is it possible to map a physical memory address to a windows user-space application virtual address to read/write?
EDIT:
I have a system where a real-time operating system is running in parallel with windows. The guest-OS(RTOS) is able to read and write from/to a memory mapped PCIe slave peripheral by mapping the physical address to its virtual memory space.
What i would like to do, is to be able to communicate directly with the PCIe slave device from a windows user space application, but this requires me to map that physical memory address to the user-space virtual memory-space.
Thanks in advance.
Device drivers can map physical memory into the address space of a user-mode process using MmMapLockedPagesSpecifyCache and the related functions. To the best of my knowledge, there is no way to do this without a device driver.

Resources