Monday, August 01, 2005
Direct Hardware Access under Windows
A comment to the previous post reminded me that many programmers would be happy to gain direct access to hardware under Windows without writing a device driver. Now, I'm not sure how much damage I'm going to do by saying this (I mean, it is not exactly a secret anyway :-) but it's actually possible to access physical memory without a driver, or to open up direct access to I/O ports for a regular user mode program.
Physical Memory is accessible by opening \Device\PhysicalMemory. Unfortunately you can't do that through the Win32 API, because it will filter out your request. You have to go one step below and use the (officially undocumented) Native API. You can find several docs on the Native API on the internet, but also in books like "Windows NT/2000 Native API Reference" by Gary Nebbet (the book is little more than a listing of functions, parameters, purpose: is not a tutorial). Complete source code for physical memory access is available at the SysInternals web site. That code uses the Native API even when the regular API is enough (map/unmap views on memory mapped files) but hey, you can fix that yourself :-).
Accessing I/O from user mode is not so straight. The best idea I've seen so far is pretty old (1996) but still working. You write (once and forever) a device driver that can modify the IOPM for a range of ports and for a specific process. Then, the process can use inp and outp to read/write from ports, undisturbed and much faster than it could go by asking a driver through IOCTL. So if you want a user-mode process directly peeking on the UART state :-), that's the fastest way to go.
You can find all the details in "Direct Port I/O and Windows NT" by Dale Roberts, Dr. Dobb's Journal, May 1996. Again, lot of drivers inspired from that article are available on the internet; some of them are free, but I'm not sure if they come with source code (if you find some, you may want to post the link here!).
Finally, you may also want to trigger some user-mode code when some interrupt fires. Again, you can write, once and forever, a driver that connects to the interrupt via IoConnectInterrupt, and then reacts by setting a named event (that can be opened from user mode as well). The user mode code will be waiting on the kernel event. Of course, you'll get a huge latency, so this is definitely not recommended in many cases.
Be aware: these are pretty much toy techniques. I've used them in a few cases, simply to avoid the creation of a custom driver under very controlled circumstances. I've also find them useful when porting old code from 16 bits Windows, where direct access to [unprotected] I/O and physical memory was possible. I don't recommend that you bet your projects on this stuff :-). Still, these toys can be very useful at times...
Physical Memory is accessible by opening \Device\PhysicalMemory. Unfortunately you can't do that through the Win32 API, because it will filter out your request. You have to go one step below and use the (officially undocumented) Native API. You can find several docs on the Native API on the internet, but also in books like "Windows NT/2000 Native API Reference" by Gary Nebbet (the book is little more than a listing of functions, parameters, purpose: is not a tutorial). Complete source code for physical memory access is available at the SysInternals web site. That code uses the Native API even when the regular API is enough (map/unmap views on memory mapped files) but hey, you can fix that yourself :-).
Accessing I/O from user mode is not so straight. The best idea I've seen so far is pretty old (1996) but still working. You write (once and forever) a device driver that can modify the IOPM for a range of ports and for a specific process. Then, the process can use inp and outp to read/write from ports, undisturbed and much faster than it could go by asking a driver through IOCTL. So if you want a user-mode process directly peeking on the UART state :-), that's the fastest way to go.
You can find all the details in "Direct Port I/O and Windows NT" by Dale Roberts, Dr. Dobb's Journal, May 1996. Again, lot of drivers inspired from that article are available on the internet; some of them are free, but I'm not sure if they come with source code (if you find some, you may want to post the link here!).
Finally, you may also want to trigger some user-mode code when some interrupt fires. Again, you can write, once and forever, a driver that connects to the interrupt via IoConnectInterrupt, and then reacts by setting a named event (that can be opened from user mode as well). The user mode code will be waiting on the kernel event. Of course, you'll get a huge latency, so this is definitely not recommended in many cases.
Be aware: these are pretty much toy techniques. I've used them in a few cases, simply to avoid the creation of a custom driver under very controlled circumstances. I've also find them useful when porting old code from 16 bits Windows, where direct access to [unprotected] I/O and physical memory was possible. I don't recommend that you bet your projects on this stuff :-). Still, these toys can be very useful at times...
Comments:
<< Home
L'articolo "Direct Port I/O and Windows NT" by Dale Roberts, Dr. Dobb's Journal, May 1996" non mi è nuovo e forse in passato l'avevo scartato proprio perché valido solo su piattaforma NT (Anche se in win9x l'accesso diretto si può fare impunemente). Ingolosito dalle risposte comunque sempre interessanti rilancio con una richiesta, sempre riguardo alle impostazioni delle porte seriali. Conosci un modo per acquisire / modificare le impostazioni della FIFO, così come si può fare premendo il pulsante "Avanzate" in gestione periferiche? Non ho mai trovato un'API ed immagino che tale informazione sia posta nel registro di sistema, ma non ho voglia di leggerlo / scriverlo direttamente...
In realta' la stessa tecnica funziona anche sotto 2000, e variazioni sul tema anche sotto XP. Se cerchi un po' trovi parecchi freeware, ad esempio elencati su Parallel Port Central.
Per quanto riguarda la FIFO: si puo' leggere/modificare nel registry (\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Serial) ma anche parlando direttamente con il driver via IOCTL_SERIAL_SET_FIFO_CONTROL. Non trovi queste cose nelle API perche' sono documentate come parte del DDK, non dell'SDK. E ovviamente sono anche ben visibili nei sorgenti forniti insieme al DDK :-)).
Un buon link da cui partire per esplorare il driver seriale di Windows "lato DDK" e' il Serial Driver Reference su MSDN...
Per quanto riguarda la FIFO: si puo' leggere/modificare nel registry (\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Serial) ma anche parlando direttamente con il driver via IOCTL_SERIAL_SET_FIFO_CONTROL. Non trovi queste cose nelle API perche' sono documentate come parte del DDK, non dell'SDK. E ovviamente sono anche ben visibili nei sorgenti forniti insieme al DDK :-)).
Un buon link da cui partire per esplorare il driver seriale di Windows "lato DDK" e' il Serial Driver Reference su MSDN...
Una precisazione: quando parlavo di Windows NT mi riferivo alla piattaforma e non solo a NT4 e quindi ovviamente davo per scontato il funzionamento su 2K, XP e 2003.
Un ringraziamento: vien quasi imbarazzo a domandare data la prodigalità con cui rispondi.
Post a Comment
Un ringraziamento: vien quasi imbarazzo a domandare data la prodigalità con cui rispondi.
<< Home





