The fourth part of Abhishek’s online UMDF debugging tutorials is up now. :)
http://www.microsoft.com/whdc/devtools/debugging/umdftraining.mspx
Next up, those of you playing with Windows 7 may have noticed that the “Found New Hardware” wizard is gone! This in itself is not that big a deal, but it does mean that some of the WDK sample installation instructions are no longer valid.
Simple fix at the end of the day, the device will come up as an “Unknown Device” within Device Manager, choose “Update Driver” from the right click context menu for that device and then follow the directions to point it to the driver(s) you need!
That’s all for today, those of you in the U.S. enjoy your 4th of July weekend. And just remember, light fuse then run away.
*Currently Playing - Dream Theater Light Fuse and Get Away
Like all good stories, sometimes the 2nd act is the hardest to follow. In this case it was simply a matter of other things coming up rather than writers block. :)
What kicked me in the rump to get this next part up was a few more questions about driver writing, WDK integration into Visual Studio and Intellisense. One of the very cool features of Visual Studio 2008 is the ability to make a project from existing code.
The end result can look something like this (warning, this is a 1920x1200 resolution PNG *g*)
I’ll walk you through this using the “a picture is worth a thousand words” mentality;
Select “Next”
Then point it to the root of the WDK installation. Pointing it to the root rather than right at the src folder will save you some intellsense headaches later on, sure you’ll get inclusion of all the WDK folders, but it’s actually not a bad thing in the end;
Select “Next”
Then;
Select “Finish” from here. We’re still not going to use Visual Studio to do any building for now, partly because I refuse to give up all command windows in my life and also because I’m still tinkering with all the settings required to use the WDK build environments under Visual Studio.
Now your Solution Explorer will probably look like a mess of files listed alphabetically. Simply hover over the “Show All Files” button at the top and toggle it until you get an Explorer like layout of the samples sources structure.
Now you have pointer to the first picture in the blog post. :)
As a side note to any Microsoft Employees who may actually read my blog – Yes, you can do the same thing with our Source Control Enlistments (I have a VS project for each branch I work out of). And if you have one of the Source Control plugs in for Visual Studio, you can also have all the check in / check out / history that our source control provides.
Our wondrous Abhishek did a series of Debugging UMDF driver talks and I’m happy to say we now have the first three live on line!
In these he covers some of the basics; where to find and how to use WDFVerifier, how to use some of the UMDF Debugger extensions and some basic debugging UMDF scenarios.
http://www.microsoft.com/whdc/devtools/debugging/umdftraining.mspx
As always, any feedback or questions you guys may have, feel free to ping me!
In my previous post about Filter Drivers, I mentioned that this time I would focus on a more UMDF centric stack. This one is pretty simple.
For UMDF only based driver stacks, the single most important directive is the UmdfServiceOrder INF directvie. As I mentioned last post, that directive is a left to right list determining load order for the drivers contained in the device stack. With the left most element in that list being the the lowest driver loaded.
Here are two examples – First a UMDF two driver stack with an upper filter;
[<mydriver>_Install.NT.Wdf]
UmdfService=UMDFFunction,WUDFFuncDriver_Install
UmdfService=UMDFFilter,UMDFFilter_Install
UmdfServiceOrder=UMDFFunction,UMDFFilter
Now to install a lower filter, simply flip the order in that directive;
[<mydriver>_Install.NT.Wdf]
UmdfService=UMDFFunction,WUDFFuncDriver_Install
UmdfService=UMDFFilter,UMDFFilter_Install
UmdfServiceOrder=UMDFFilter,UMDFFunction
The last tidbits here are; for a device stack that only contains UMDF drivers, there is no need to add any of these settings in the INF;
[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd"
And also as before, the filter driver needs to be a good citizen on the stack, pass on requests it does not own to the next driver and don’t touch anything unless you must. The previous code samples I’ve posted all still apply, but the basics are; GetDefaultIoTarget, FormatUsingCurrentType and Send.
There’s no need to change any code for a basic filter driver based on its load order (upper or lower filter). As you get in to more advanced driver functionality you may find a need to change default behaviors. For those cases, you can always send us mail. :)
There was also some questions about why would you want or need to be an upper or lower filter driver. That one gets in to a bit more of a “it’s up to you” but the core logic that applies to WDM / KMDF drivers applies to UMDF drivers (save the parts about bus drivers *g*).
Oracle Buys Sun - Gearlog
I’m not sure how to feel about this. I know it probably went under a lot of people’s radar, but it almost feels like the passing of a rival. Something you wished would happen earlier, but not something you really wanted to happen because they made life interesting. Scott McNealy’s keynote blastings of Microsoft were legendary and at times very humorous. The “we’re the dot, in dot com” ads always gave me a chuckle. Yup, they part of what made being an employee of Microsoft during the late 90s and early 2000s fun.
It wasn’t all about the products, they made hockey interesting as well. There were a few charity Sun v. Microsoft hockey games played through the early part of this decade. They ended up being events all to themselves. A good way to let out some frustrations and have some fun with your rivals at the same time.
All in all it was a good little feud, some barbs, a little blood (very little at a hockey game) and a lawsuit here and there. But as a good feud should do, it drove of us to make our products better in the end.
Bon chance Sun.
That said, ol’ Larry Ellison has never been a close friend of Microsoft either. :)
I’ll have the next part in the UMDF Filter series later this week.
Filter drivers have come up in conversations recently (both internal and external), so I wanted to take some time here to address some of the issues that were brought up with regards to UMDF filter drivers and how to make them. Note: I’m not going to cover all the configuration dynamics available for UMDF filter drivers in this one post simply to avoid the risk information overload and clutter, so expect a couple of posts on this subject.
Let’s start with some basics, we’ll simply demonstrate how to configure and load a UMDF Filter as an upper filter driver to a kernel mode driver (KMDF or WDM) in the same INF-
As some of you may remember from my earlier posts, a UMDF filter driver should use the SetFilter(); property in the DeviceInitialization routine. This tells the Framework to do a couple of things for us automatically:
- Send I/O for which the Filter has not registered a callback for to the next logical driver in the stack. Example: Your filter driver registers a DeviceIoctl callback method, but not read or write. As a result your filter driver will only see IOCTLs
- Automatically forward file create cleanup and close so there is no need to invoke the AutoForwardCreateCleanupClose method.
That covers the really basic code required at driver / device initialization time. Now we need to add the pertinent sections to the INF file. As we’re going to focus on being an upper filter for this example, you need to make the following modifications to your INF (in addition to the normal UMDF specific sections);
[<mydriver>.NT.Wdf]
UmdfService = "<mydriver>", <mydriver>_Install
UmdfServiceOrder = <mydriver>
[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd"
So a couple of things to note here -
One is the UmdfServiceOrder directive, this is load order specific. I’ll address a more UMDF centric stack in the next post, but for those of you who like to work ahead, this is a left to right reading list to determine stack order.
Second thing is the registry key addition section. As WUDFRd is the kernel mode transport service for UMDF drivers, WUDFRd is the upper level filter driver to a kernel mode driver.
Now that your driver is loaded as an upper filter, what should your driver do in order to be a good citizen in the stack? Short answer is, as little as possible. You perform the same steps for handling PnP and Power as you would for any basic UMDF driver (one that lets the framework handle the heavy lifting for those two). You register your I/O callback routines and build your queues just like any normal UMDF driver, the only additional requirement here is to forward I/O requests as required.
For this example, let’s just demonstrate using a fairly simple pass through driver. How you actually implement this is up to you, but the basic requirements here are - as your driver receives the request on the queue, it needs to pas pass it on to the next driver in the stack. So first you need to get the default I/O target (next driver in the stack). Next, format the request using the same type and then finally, send the request. A condensed version would be something along these lines;
IWDFIoTarget * kmdfIoTarget = NULL;
this->GetFxDevice()->GetDefaultIoTarget (&kmdfIoTarget);
Request->FormatUsingCurrentType();
hr = Request->Send (
kmdfIoTarget,
0, // 0 Submits Asynchronous else use WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
0);
I also have some more basic code here for you to peruse.
So now we have a basic UMDF upper filter driver on top of a kernel mode driver.
Now Playing Capitals v. Rangers
Yes, I'm alive, and in perfect hibernation, well not even in the same time zone as hibernation, but you get the joke hopefully. :)
I just had to share this little ditty with you all because it's very cool.
Microsoft, NASA put universe back on the Web | Webware - CNET
I will resume regular technical type blogging shortly. Enjoy!
*Currently playing - Porcupine Tree Signify
Yes, I know that's a rip off of a ThinkGeek shirt (which I own).
Well, this is going to be my second post on this topic (okay, third), but as it managed to rear its head again recently, what better time to blog. And I'm going to also blog it simply to prove to Doron that I can provide something other than comic relief.
You'll notice a few of the existing UMDF samples have their locking constraint set to WdfDeviceLevel in their Device Initialization routines and some others don't set it at all, which defaults to WdfDeviceLevel.
So, what is the problem with doing it the way some of those samples are? Well, it does put the widest locking scope on all your objects that the device holds, meaning the device framework acquires a device presentation lock before passing some I/O to their driver callbacks. This results in serialized calls to that callback for your file and queue operations which is really unnecessary. There's a really good table in the Windows Driver Foundation book (pg 390) that shows what callbacks are serialized when using the Device Scope level. And to save some of you looking it up, I'll tell you now that yes, OnDeviceIoControl, OnRead, and OnWrite will get serialized if you set the locking constraint to Device Level.
So unless your driver really requires a synchronization scope that wide, initialize that constraint to None;
HRESULT
CVDevDevice::Initialize (
__in IWDFDriver * FxDriver,
__in IWDFDeviceInitialize * FxDeviceInit)
{
IWDFDevice * fxDevice = NULL;
HRESULT hr = S_OK;
FxDeviceInit->SetLockingConstraint (None);
{
IUnknown * unknown = this->QueryIUnknown ();
hr = FxDriver->CreateDevice (FxDeviceInit, unknown, &fxDevice);
unknown->Release ();
}
if (SUCCEEDED (hr))
{
m_FxDevice = fxDevice;
fxDevice->Release();
}
return hr;
}
The primary differences here between KMDF and UMDF are UMDF doesn't set an execution level, so the likely hood of you bug checking by screwing this up is greatly reduced. :)
Edit: For those on RSS, sorry about the embedded style sheet nonsense, I keep forgetting to clear that tick box
*Currently playing - King's X Silent Wind
Greetings from the Pacific Northwet. After our recent Snow-pocalypse, we also suffered a run of flooding. Amazingly enough, it wasn't directly due to the 13+ inches of snow I had at my house, it was a combination of the snow and the monumental amounts of rain that followed. Quite a few people were literally cutoff from the rest of Washington State as their egress roads were under rivers. The only hassle I had to suffer was one of FedEx being a day late with a new laptop. Oh bother.
The leaking I did have to suffer was of my own doing. It was my usage of IWDFIoRequest::GetCompletionParams in a test driver. In trying to be a good boy and clean up my I/O requests, and especially since I was going to be using asynchronous I/O, I wanted to get the completion parameters with out having to mess around with a completion routine. Funny thing is, that call takes a reference on the pointer returned. All was fine and dandy until I turned on Object leak detection (using WdfVerifier) and reference tracking. Debugger breaks prevent things from running smoothly I've found. :)
Now those of you much smarter than me would have told me I could have avoided that by using the CComPtr class on the CompletionParams interface as shown in the sample, but if you're like me and still think you know better and didn't use the CComPtr class, you had best make a subsequent Release() call.
pWdfRequest->GetCompletionParams (&CompletionParams);
hr = CompletionParams->GetCompletionStatus ();
CompletionParams->Release();
Now to answer a question nobody asked, yes my dog LOVES snow.
I'll spare you all part two of my FiOS TV installation rant because the guy who came out and installed the CableCard in my TiVO made up for the previous incident, ten fold. All I can say is wow. I really enjoyed watching Rush R30 in un-bitstuffed HD via the Palladia channel. Thank you FiOS.
*Currently playing - Porcupine Tree Blackest Eyes
WARNING: Rambling and ranting ahead. Read at the risk of losing time you could be spending doing other things!
As I noted in my last post, I was to be migrating to FiOS TV on 21-November. Well, first let me say that every person I've talked to on the phone with Verizon has been very nice and helpful. Even if they weren't able to help me get things resolved.
You'll notice there's a decidedly inclusive statement there. Every person. As you guys have demonstrated to be quite the smart bunch, you probably will have gathered that I've been on the phone with Verizon a number of times recently. So here is the first part of my frustrations with FiOS.
All was going well on the 21st. I had a scheduled time between 10-12 and they had informed that I would be called ~30 minutes before they showed up. As I was on vacation that day (and the subsequent week), I decided to see if I couldn't cut down on some of the installation steps they needed to go through by disconnecting our DirecTV boxes and getting the A/V rack in the living room setup for easy access.
I had been told that since I had FiOS Internet service already, the TV service install shouldn't take more than a couple of hours. They simply had to run cable from the Optical Network Terminal (ONT) to the exiting cable lines in the house then simply setup and then register their Set Top Boxes (STBs). Well, much to my chagrin, 15:00 rolled around and I had heard nary a word from the installer. So I called the lovely people at Verizon and asked where my installer was. I know those windows are rough estimates and that things can (and often) do creep up in other installs. Which is the reason I had waited until 15:00 to call. Three hours past my window is reasonable in my opinion.
The very helpful man on the other end of the phone apologized, and then placed me on hold in order to call the installer and find out what was going on. When he got back to me, he apologized again and said that the installer was about 90 minutes away from completion of the other job. My first (and biggest gripe really) is that I never got a call from the installer saying he was running behind.
I have another slight problem here and some of you can probably figure out what that may be, but I'll explain it later.
I wasn't happy with that result, but what can I do at this point. I fired up my Xbox 360 and started watching some episodes of 30 Rock over Netflix to keep me occupied. For some reason that was allowed to last for another 3 hours.
Yes, 18:00 rolled up on me and still nary a word from the installer. From being done with the previous job in 90 minutes to 3 hours passing and still not a word. Yup, at this point my patience was gone, I had been with DirecTV for 14 years and had never had anything close to this happen. This was the kind of service I expected from Comcast honestly, not Verizon. My FiOS Internet installation experience was awesome, end to end. The guys that came and did the service, their handling of my request during setup, the whole show was great.
Anyway, I called Verizon again at 18:00 and told them I no longer wanted any part of this, I had yet to cancel my DirecTV service and I'd be more than happy to carry on with them if this was how things were going to be handled. They were very apologetic and informed me that I would have to be transferred to my local billing office to cancel the order. Which they kindly did, or at least attempted to do... Yes, I was transferred only to find out that my local billing office closed at 18:00 PST, and would not be back open until Monday morning.
18:30 the installer called. He had the gall to call me and submit that he would be more than willing to come out and do the installation right now. By 22:00 he was finished with the install. Now let me be very clear here, the ONT was some 25' away from my existing cable feed to the house, we only had two STBs to be installed (which I did in about 5 minutes while he was outside, 2xPower Outlet + 2xHDMI = 2xDone).
All he had to do was run cable from the ONT to the existing line in to the house, then come inside and run their little registration application to log the boxes as live for service. That took nearly 3 hours.
So here's where the race condition comes in - After doing all the exterior work, he came in to register the boxes, which partially failed. The DVR STB had a partial registration, the other failed wholly. After another 30 minutes of retrying and resetting the boxes, he called their Technical Support center to find out...they had taken down the registration servers for maintenance. Meaning I had one box in my house that only got part of the programming package I had paid for, the other box wasn't functional and my multi-room DVR service was not functioning. The kid doing the install apologized ad nauseam. At this point I seriously just wanted my DirecTV back. But again, I'm a sucker for new technologies, and I was already on this boat floating down the river Styx, so might as well ride it out.
At this point the kid promised he would get the box registration done tomorrow morning first thing and I'd be up and running by the time I got up. Sure enough, he kept his promise on that one.
Now in my "playing" around with the STBs Saturday morning, I discovered that my multi-room DVR was not working. One of my reasons for moving to FiOS TV was so I could watch stuff recorded on the DVR in my bedroom with out needing to have another DVR. So I called my new friends at Verizon FiOS tech support. The lovely lady had me run through some of their STB menu items for her, then she showed me the super secret method to access the STBs diagnostic and installer menus. Everything in there checked out okay on both boxes. Which left her stumped. So she put me on hold to talk to the senior support person. Upon her return, I was informed that the two boxes the installer dropped off were incompatible. Yes, you read that right. So after hanging up and entering a fit of cursing, I decided to call back again. This CSR person was stumped as to why the previous person told me such a thing. So after he and I went through the same things, he asked me a few more questions and then told me they might actually BE incompatible. But he was asking a senior technical support person a few questions.
In the background I can hear the familiar noise of the MSN Messenger service. A few "mmm" and "ahhh"s later he informed me (via his contact over Messenger)that they WERE compatible, but for some inane reason the registration application he was using wasn't resetting the feature flag on the box, so he was going to use his super secret registration application to fix this. A scant 2 minutes later, it was working just fine. All was well in my house finally. It only took 18+ hours to get my FiOS TV installed and running 100%....well not really 100%.
So in deference to the one person who managed to read this far, I'll let you have a break before I start with the second Act. :)
Now, there's one thing in this that I'm sure some of you have picked up on, and I lightly called out previously. It's way back at the top of this babble; my installation window was set between 10-12. I would normally assume that I was 2nd or maybe 3rd on a list of work items for that person on that day. And my assumption here also was that none of those work tickets prior to mine would take more than a couple of hours.
According to the kid that did the install, every work ticket he got was setup between 10-12 and they stacked him up with 6 or 7 of them.
Yeah, I thought the same thing.
Thanks to the intrepid reader, TJ, who notified me that NHL Center Ice was now available on FiOS TV. After 14 years of service, I will bid a adieu next Friday to DirecTV. For those of you wondering why I've been touting FiOS, it's currently the only TV service that does not recompress their HD signals before throwing it down the wire. Well, other than OTA, but show me where I can get Montreal Canadiens or San Jose Sharks games in HD via OTA in Seattle.
Just so this post isn't devoid of anything other than another gloat, here's something we were just throwing up to stumble each other;
void
main ()
{
int * m;
m [1,2] = 5;
}
This does what?
Some of you may remember much earlier this year I had upgraded my FiOS package to 15/15Mbps. Well some time between then (February) and a few weeks ago (late October), I discovered that the price for my 15/15Mbps package was the same as the newly minted 20/20Mbps package.
Needless to say I called Verizon and let them know that since I was paying for 20/20, I'd really kind of like to have it. Pay no attention to the distance, my IP address is flagged as being from the Toronto area. Which is even more humorous considering how much I pick on Toronto.
They're offering FiOS TV in my area as well. But as I've told every Verizon person that I have talked to, "No Center Ice, no deal". You have no idea how much that pains me.
That's all I had for you today. Gloating. ;)
*Currently playing - Transatlantic All of the Above
Bob, Peter and Ilias are on their way to WinHEC as I'm typing, so if any of you are attending, please make a point to ask them if they miss me. :)
A while ago I was debugging something in my office and I had an observer over my shoulder. This observer was shocked to see that I still used a command window based debugger, good ol' KD. "But you can debug with source code and have all these windows open that show registers and local variable values..." I get that in KD as well. As Doron showed a while ago, the 'trace' command provides you a nice stepping stone(pun intended), but combine that with an 'r' (tr) and it displays the registers as you walk along. So right there is all I ever needed to debug.
Now you can start having some real fun; trace to address, trace to next call / return, and then for the icing on the cake, break on access. I don't need a GUI debugger, I like to live in the world of black and white, well actually just to be even more old school;
I'm still trying to figure out how to replicate screen burn in on a command window. ;)
So on to some random housekeeping - No I haven't played Fallout 3 yet. Yes I have it. No I haven't played GoW2 yet, I didn't land on any internal betas so I have to wait for retail release. And finally, no I haven't played Fable 2 yet, the company store was sold out.
I think that's it for now.
*Currently playing - King's X Freedom
Most of you at the DDC will notice that I'm not at the DDC. I'm guessing that makes me one of the "juniors" that Bob was referring to. ;)
4.) How do you build debugging techniques into your driver? Ie, DbgBreakPoint, ASSERT, etc - which is best in various situations?
This is one of those personal preference type questions. For the sake of lineal chatter, I'll just use ASSERT in my commentary. But when I say "ASSERT" you can make the determination on which one to use given your own working methods.
So that preamble aside, it's on with the show. I like to have staged text output via a debug trace level as a first tier technique. Something along these lines;
#define FILTERNAME TEXT("mydriver")
#define DRIVERNAME FILTERNAME TEXT(".sys")
#define DRIVERNAME_DBGOUT FILTERNAME TEXT(": ")
#if DBG
#define DBG_TRACE_VERBOSE 0
#define DBG_TRACE_MINIMAL 1
#define DBG_WARNING 2
#define DBG_ERROR 3
#define DBG_FATAL 4
extern unsigned char DebugLevel;
#define DBG_PRINT( l, _x_ ) \
if( (l) >= DebugLevel ) \
{ \
KdPrint((DRIVERNAME_DBGOUT)); \
KdPrint( _x_ ); \
}
#else // DBG
#define DBG_PRINT( l,_x_ )
That allows me to compartmentalize failures and thusly allows me to build handlers for each. The question of what to do in each of those situations is another personal preference. As you can see from the error levels above, I follow patterns of building in handlers that fall in to - terminal, really annoying, nuisance, does it work and assuage.
I'll ASSERT more frequently for the nuisance issues, but also for the terminal, and some of the really annoying issues. Nuisance issues such as that HANDLE disappeared while I was using it, better ASSERT. This is usually when I find that the other thread using that handle wasn't synch'd properly...laugh all you want, you've done it too. :)
Using those levels as a guide, I craft an appropriate follow up action. But here I let the driver tell me what to do and it does that based on its end usage. For example;
Status = IoCreateDevice (
DriverObject,
sizeof (DEVICE_EXTENSION),
&DriverName,
FILE_DEVICE_UNKNOWN,
DeviceType,
FALSE,
&DeviceObject);
if (!NT_SUCCESS (Status))
{
DBG_PRINT (DBG_FATAL, TEXT(("Failed IoCreateDevice: 0x%x\n", Status)));
ASSERT (DeviceObject);
return Status;
}
Would I use that ASSERT in a test driver? Not likely, all too often our test cases attempt to invoke failures in just those sort of areas and we run chk (debug, no_opt, etc.) builds in our labs frequently. So that ASSERT would be triggered constantly. You could also argue that in a shipping driver you would hit it in a lab under low resource simulation testing, but unless you plan on running low resource simulation 24/7, the nuisance factor is diminished greatly. But having the debug print there is a means for you to see if something happened in a retail / fre build of the driver. You can also wrap Windows logging methods with the same mentality such as WPP and ETW.
All of the above starts with the driver though. The more complex the driver, the more robust the debugging logic, so some of my internal test drivers have one or two ASSERT calls and maybe a couple of lines of debug print statements. So if you peek at the 1394vdev hybrid sample you can get a better idea of my patterning. The lack of ASSERT calls was a design choice based on the pattern established by the previous versions of that sample driver.
So for those of you at the DDC, enjoy the DDC! If you feel like making Peter laugh, ask him why I'm such a dork.
*Currently playing - Gravity Eyelids Porcupine Tree