WWDC2001 Session 207

Transcript

Kind: captions Language: en good afternoon and welcome to the USB in-depth session we're going to go into USB both for user client and kernel level deep development I'm Craig Keithley I'm the USB and firewire technology manager actually I'm one of two Greg Mullins also in my group is another USB and firewire technology manager so with this session we'll go into what's involved with writing user level drivers and kernel level drivers we'll do some demonstrations on debugging and with that I want to introduce Fernando or bina Andros Halliwell thank you very much Thank You Craig we have a lot of topics to cover today so why don't we just get right on it today we're gonna give you an overview of the IU USB family class in Mac os10 talk a little bit about the objects that we have and how we use them in in the kernel we're going to go into some detail into writing kernel and USB drivers and how to decide whether it be in the kernel or in user space a very very critical part of writing drivers is how to match your device to your driver so we're also going to go into quite a bit of detail into that and at the end of the session we'll show some demos on how to debug and USB drivers in the kernel and in userspace as you probably know you will need to use a project builder which is a both integrated development environment to write both kernel and user space drivers if you are writing user space drivers you will be able to use the debugging features of project builder to debug your driver unfortunately if your kernel-space driver you will have to get down and dirty with gdb and terminal and debug your drivers that way later on I'm gonna talk about whether you should write a user space or a kernel space driver this is the first decision that you have to make when you decide that you're writing a USB driver for Mac OS 10 so so it's a very important to to know what you're gonna do there if you are in the kernel you will be able to use io qids object-oriented features so for example if you are writing a driver that is gonna be subclass from our mass storage driver you will only have to write the methods that you are overriding to to implement your device specific features so it's a very convenient way of doing it roads we'll talk later on about user space drivers in some detail and as was mentioned in the previous session fire wire we use the device interface model in order to communicate between user space and our internal IO USB family objects the USB family is in the kernel there's a four or five objects that we provide they are delivered as a kernel extension that goes in the extensions folder we use this facility to update USB without having to give you a whole new kernel user space drivers can obviously access the internal objects through the device user or the device interface client that I mentioned earlier this light gives you just a brief description of the internal objects for the audio USB family those are the ones in in purple and in a later slide I will talk in some detail about them I just wanted to give you a an overview of where we fit within the user space on the kernel space so let's talk a little more about kernel mode USB drivers how do you decide whether you're going to be in the kernel or in user space if at all possible you should not be in users you should not be in the kernel sorry however in some cases you don't have a chance if you are writing a vendor specific driver for a keyboard you need to be in the kernel because at boot time if you're going into single user mode in the Machine you need to have a keyboard there's no user user land processes running at that time so you're you have to be there the other condition is if your clients live in the kernel for example mass storage or networking client the file system or the tcp/ip stack they are in the kernel you have to be in the kernel and so you don't have you don't have a choice again if you haven't gotten the message we really recommend that that you are that you write your drivers in the user space there are a lot easier to debug if you're in the kernel it's really easy to panic the machine and users don't like that so try to write user space drivers the just like all other iokit drivers USB drivers are written in the subset of C++ the base class of all iokit drivers is IO service when you write the driver in order to load it against your device you will need to provide a matching dictionary so that we can load and later on we're gonna show you on the demo machines the different fields that go into a into a dictionary and how we decide on how to match it against your device the driver itself that project builder makes is a text package that goes in the extensions folder and as as we mentioned earlier in the previous presentation that IO us be family or your driver can include sub drivers in the one package this slide just gives you a overview of the different USB family objects that are in the kernel the IO USB device IO USB interface and I owe us beep I'm going to talk in more detail about each after this slide we also have two other objects which are the i/o USB device user client and IO USB interface user clients these are the user client objects that are used to communicate between user space and our internal objects when you plug in a USB device into a bus our family will create a io USB device object for that device the provider of that device will be the IO USB controller class the IOU io USB device object it's an abstraction of the physical IOU we devised this class provides methods for accessing the device descriptor fields of the USB device we also provide methods for getting the configuration descriptor of the device and also for setting the configuration for the device once you set the configuration for the for the device the family will go ahead and create I O USB interface objects for all of the interfaces that are in that particular configuration the i/o USB device class will be the provider for all these IOUs B interface objects again there is gonna be one I owe USB an interface object for each interface in the particular configuration figuration description of the device the interface objects are an abstraction of USB interface the methods that we provide for the USB interface are those that allow you to access the fields of the interface descriptor and also allow you to set alternate interfaces if they are available for your interface when we create the i/o USB interface object we will also instantiate IO USB pipe objects for each of the pipes in the in the interface there will be one for the default control endpoint and we'll also create however many objects that are needed to match against all the other endpoints that are specified in the face the scripture the methods that we provide for the IOUs be pipe objects are those that are needed to actually communicate with the device so we have the reed pipe we have the right pipe we also provide methods to get status on the pipe to clear the a possible stall on the pipe and cetera the other two objects that we have as I mentioned before are the i/o USB device user client and the i/o USB interface user clients and these provide the necessary glue for a user task user driver to talk to the internal objects you could tell whether you actually have a user task attached to your device driver or your interface driver by using the i/o register Explorer going down the tree to find your driver node and you can then see if there is actually one of these user clients attached to it the convention that we use for in our family for the Apple supply drivers is the following if the driver starts with the i/o letters we intend that you could subclass that driver and add functionality just by defining new methods or overriding some of the base class methods if the driver starts with the word Apple that is ours and you're not allowed to subclass it however if you have a vendor specific device you could just get our code adapted to what your device does and unuse it that way and create your own driver this is a list of the USB drivers that we are providing the kernel these are the all the Apple ones it's the standard Mouse keyboard hub driver we provide just like in mac os9 a composite class driver that will just look at that configuration find the first configuration and do a set configuration on that device to create the interfaces for that device the to subclass able kernel drivers that we provide are the head driver and the mass storage class driver again the nice thing about living in the kernel and being able to use these drivers is that if your device just is a little different than one of the devices that we support you can just use C++ and override those methods that you need to change and you have a lot simpler driver than starting and writing everything from scratch those of you who attended the USB overview session yesterday pro will recognize the following two slides but we are including them here because we think it's really important to understand how the drivers stack of the USB drivers is built up and in the next slide how it all fits together so again the i/o PCI family will discover the ohci USB controller and it will load a driver for that device that is our i/o USB controller driver during startup this controller driver will instantiate a IO USB device for the root hub of that controller we use iokit methods to match a driver against that device and we have the Apple USB hub driver the hub driver sits there waiting for devices to get plugged in and for example if you suddenly plug in a pair of speakers the Apple USB hub driver will notice it will enumerate those speakers and it will create an i/o USB device and attach it to the i/o USB controller in this case for this example speakers are usually a composite class device so the composite class driver will go ahead and load against this i/o USB device it will do a set configuration on it which is as I mentioned earlier will load V or create the i/o USB interfaces for that device in this case I'm only showing one of those interfaces the again we use the i/o kit matching code too as for a driver to be match against this interface and we have the Apple USB audio device driver loaded against it so this is how in this works and any device that you plug in will do the same thing and we'll try to find drivers for it and and instantiate them for your device as long as they're in the kernel this driver is sorry this slide is here to show a distinction between being a driver and the distinction the one that we want to make is who your provider is and what member of which family you are for example the Apple USB audio device is a member of the i/o audio device this is the base class from which they derive they get their behavior their API from the i/o audio device family however when they actually want to send data to the pair of speakers they use the i/o USB family as the transport mechanism to get that data from memory down to the speakers so it's sort of a dual relationship you are a member of the family but you are a client of the transport family which in this case is the IOUs B family but it could be another another mechanism another family if there were firewire speakers you could have firewire in this example the Apple USB audio device is is a leaf node driver so isn't it is not intended to be subclassed however if we had the hit driver attached to an interface like for the buttons of a speaker as you've seen in other slides it has a little puzzle piece which means that you could subclass that that driver and add the functionality that you need in Mac OS 9 we had a DDK that provided some example drivers some of them we or most of them we used internally at some point but there weren't the live sources that we were using to release the USB stack on Mac OS 9 that has changed with Mac OS 10 we are open sourced we live in the Darwin repository so our live IO USB family sources are there the module name is the i/o USB family no surprise there if you haven't gone and become a member of the open-source project so that you can check out the sources you should go ahead and do it download it look at the source look at the drivers borrow whatever you need tell us where we have the bugs it would be nice if you said you know 9:23 of such-and-such a file but if it is there for you to look at and we go we went through a lot of effort to get this out out into the open source community so you are more than welcome to go ahead and look at it okay IOUs be family driver matching if we cannot drive your driver if you cannot if we cannot match your driver to your device then you know game over why have the driver so it's very critical that we explain it so you can get it right and the first item that you have to decide is are you going to be other than being in Colonel versatile user space but once you have decided that you are a kernel driver you need to decide whether you're a device driver or whether you're a composite driver you will specify in your driver personality and we'll show you a demo of where that goes in a little bit whether or you need to specify the i/o provider class other iokit drivers use the i/o probe score inside the personality to give a hint to I okayed of how important this driver is what the ranking is in the i/o USB family we do not use and you do not need to provide the i/o probe score this is because USB and the USB specs have a very definite set of criteria that spell out how multiple drivers are ranked and which one has the highest rank and which one has the lowest rank so that if we find n drivers we can rank them and we can tell I okay okay try this this driver first in this manner if we provide a class driver for one of your devices for example a mouse driver you still can provide a driver that has a higher matching criteria and I okay will load that driver first and give it a first shot at controlling the device so again the USB common class specification is document that details exactly what fields you need to have in your personality to match against drivers and just by chance here I have a copy of the table that is used by the common class spec to specify device as opposed to interface driver rankings all the fields in the boxes are fields of the USB device descriptor at the top level with the highest possible rank that a driver can have is a driver that specifies the product the vendor and let's call BCD device but it's the release number of the device one step lower we have the vendor and the product that will just match against all drivers of that vendor and product ID without caring about the release number down in the orange boxes we have what we what we call the class drivers these are classes that are not vendor specific and that is what the 0xff means and you can match against the class the subclass and the protocol in the next-to-last item or just device and device subclass so as we're going to show you you're gonna specify these and this is what the USB family uses to generate a probe score for iokit to decide which driver is the highest ranked driver as was mentioned in the overview yesterday once IO kid has a list of drivers that match to a device it will give each driver a shot at denying whether they want to control that device or not by calling the probe method of that driver the default implementation for 4 probe method is to just return success so you don't even need to implement that but it is just here to give you a shot at a denying control of the device later on you still get another shot at the 9 control of that device once the ordered list of drivers with a higher one at the top and the lowest ranking one at the bottom is created I okay we'll call the start method for the highest ranked driver first this tells you that your driver is really starting you can do do all your stuff that you need to do to to get your driver in working condition if you return false from this method then I okay we'll go okay well he didn't want it let's try the next one in the list so you get this second shot at it but now I'm gonna show you or here roads is going to help me out if we could have them on one machine on the slides I'm going to show you how to specify the matching dictionary so we have the project builder this is a sample vendor specific driver that we wrote and this pane that we see up there is the bundle settings tab of the project builder target in there we have a iokit personality dictionary entry this is where the matching criteria among other things is going to live the first item the I'm gonna talk about here is the CF bundle identifier this string needs to match match the CF bundle identifier that is declared in the upper level the best way to do it is just to copy and paste because if it doesn't match your driver won't get loaded the next field is the IO class field this is the class of the driver that that you're going to use so here we have the header file where the C++ my software vendor my software company class is defined that is what you need to put in that entry next you need to tell us whether you are a device driver or an interface driver and so you specify IO USB device or IO USB interface in this case we have a vendor specific device driver so we have IO USB device now we don't have here and but Roach's gonna type in we decided to make this a vendor specific device driver and we're going to type in the common class spec fields that are required for that for that device and it is the ID product it's a number and the ID vendor and it's a number those numbers correspond to the obviously the product and device fields of the of the device descriptor finally we have this i/o kit debug dictionary entry this is used internally within i/o kit to put debugging information out to the console to the system log it helps some in debugging why your driver doesn't load from an i/o kit perspective however right just says that matching failed it is also used internally within I okayed for other other features it is a actually a bit field of different features but if you put 65 535 in it it will you know match to all the features and it will put out a lot of data we do realize that right now it is very frustrating to determine why your seemingly good driver is not loading against your device when you plug it in we are very aware of this and yeah it's not going to stay like that for long we will use the i/o kit debug field to actually put some meaningful information out to the system blog to give you an idea of what what's going on when we tried to match your driver the final two two entries in the bundle settings tab here are the always bundled libraries this is a dependency entry it tells a akkad that this driver is dependent on the Condor Apple dot I owe kid I owe USB family version 1.8 if you were depending in the future against an API that was introduced in version one point eight point seven you would put here one point eight point seven and I okayed one wouldn't even load you if the IU USB family version one point eight point seven was not around so that way you don't have to do runtime checks whether a particular API is available like you used to do in Mac OS 9 the final property is the OS bundle required property there is a a driver matching that goes on very early on during the boot process this property tells iokit which drivers need to participate in this early driver matching for example our mouse on our keyboard drivers have this this property because you as I mentioned earlier need the keyboard to go into single user mode the reason I mention it here is because if you are writing a vendor specific keyboard or mouse driver and you want to override our USB class driver you need to also put that property there if not what's going to happen is the early-on driver matching during boot time will load our class driver and then when I okay well I okay then won't even scan your keyboard or your mouse for our driver because it already has one loaded so you need to specify that if that is what you are doing we could go to the slides now again this slide shows you which I okayed methods are called during the two-step driver loading process the first step is when I okay it is looking for drivers for a device as I mentioned earlier the probe method is here which gives you a chance to to deny your your your matching you get the you need the attach the probe method and then you get detached again once I okay decided that you are the one that you are the driver who is going to control that device you get an attach method again and then you get the start method the thing to take out of this slide is that your attach method will get called more than once so you have to be prepared to deal with it when your device gets disconnected we get the file following a termination sequence you first get a message method with the k io services terminated message this is your clue that your provider is gonna go away you need to cease and desist all IO to your device you need to stop everything returned from it then you'll get a terminate message followed by the other sorry terminate method call followed by all the other ones that I list here in the slide the key there is the the first notice that you get that your device has been unplugged is is this services terminated message if you have your provider open your device or your interface you need to close it at that time now if we could go back to the demo machines we have a vendor specific driver there is a very dummy driver all it does is it spits out IO logs which by the way an IO log will print a message in the system console every time that the that the message is called and is just to prove you that is it's not smoke and mirrors and we are actually calling all those methods in the in the order that we said so here we have a security dongle and roads here is going to load the driver so that it's available for when we plug in the device he'll then open or do a tail on the console log so that we see any messages that get displayed when we go ahead and plug the device when it crashes no whoops there we go we get the init method followed by the attach the probe the detach and again the attach method and finally the start and we successfully start and there we go now when we disconnect the device we unplug it boom we get all the other methods and your driver after a minute or so will actually get a little different memory so now I'll give a key span to Rhodes and he'll tell you more about user space drivers all right we need to go back to the slides please well actually there was one more thing about the colonel that we wanted to talk about because this has been a subject of recent discussion on the USB mailing list and there's some some confusion about it and this has to do with work loops with an i/o kit IO kid has a concept for kernel threads of a work loop which is a work loop that's protected by a lock similar to a secondary interrupt queue if you will under OS 9 the biggest difference is that with Mac OS 10 this secondary interrupt queue there's more than one of them there's generally one per hardware interrupt source so in the USB family we have a work loop and we will generally have at least two because we have two separate USB controllers and so there'll be one of these work loop per controller every member of the USB family that's attached to a particular controller and every driver of any of those USB family mechs which controls a device or an interface say participates on this same work loop which is a way of serializing calls to the bus and what this means is that your driver has to be careful about what types of calls it makes to USB because if it is in a callback routine for example an asynchronous callback routine and it issues a synchronous call to the bus that call cannot complete and you have a deadlock because in order to complete an interrupt has to come in on a different thread and that interrupt will not be able to execute on the work loop because the loop is locked by the callback routine so we need to be aware when we write our drivers about what the execution context is in which thread is currently active on the work loop and if necessary you may move the thread context to a different thread using a kernel mechanism called the thread call mechanism the stuff is being discussed on the USB mailing list over the last few days and I encourage you to understand it from from that list okay I want to talk about USB in userspace as we have said before Apple strongly recommends that if at all possible you write your USB driver to operate in userspace it's much easier to debug there are better debugging tools and in general if your driver crashes you're not going to bring the entire system down which is much easier in the valley in the development stage as well as in the end-user stage now within the kernel and as this slide shows the the stuff below the kernel boundary here we have our members of the USB family so we have in this example an i/o USB device object the USB family provides a mechanism for communicating from user space to that IO USB device object and that mechanism involves two pieces on the user side it is something called an i/o USB device interface and on the kernel side it is something called an i/o USB device user client these two pieces come together in pairs and when your user land code for example in this case a USB scanner driver wants to communicate with the kernel object in this case the i/o USB device it uses those pair of objects there is also a user client object and a device interface or an interface object used to communicate with an i/o USB interface object in the kernel unfortunately the the there is some confusion because the generic name of these objects in user spaces are device interface objects and of course both of those terms were already exist in the USB world because of device descriptors and interface to scriptures and so what we really have with USB is we have IO USB device device interfaces and IO USB interface device interfaces which of course is difficult to say much less fit on a PowerPoint slide so we have shortened that to be a device interface and an interface interface so what do you need to do if you're going to write your your USB Driver code and user space well you need to use two frameworks in particular the core foundation framework which gets you access to things like CF plugins and CF run loops and the i/o kit framework which gets you access to the i/o kit functions as well as the USB functions which are part of the i/o kit framework this mechanism uses as I've said before the CF plugin model and the two plugins provided by USB are the i/o USB device interface plug-in and the i/o USB interface interface plug-in we do not provide an interface plug-in for the i/o USB pipe object this this is encapsulated within the plugin for the interface mostly although there is one pipe in the device which is the default control pipe but the other pipes are all part of the interface they are in the kernel those pipe objects are instantiated when the interface is opened and then you have access to methods within the interface interface plug-in to determine the characteristics of a pipe and to then send and receive data over any of the given pipes the iokit API is in as I said in the i/o kit framework and it's in much of it is in the i/o kit Lib dot H file the plug-in API that we use is also in the i/o kit framework and it is in IOC F plugin dot H and then finally the USB interface API is in the i/o kit framework in the USB subfolder and it's in IO USB live H again the two interfaces we provide four USB drivers are the i/o USB device interface and the IO USB interface interface so if you're running in user space you need to communicate with a kernel object either an i/o USB device object or an i/o USB interface object so how do you do that well the first step is to find the correct kernel object this these procedures by the way are outlined in a in a document available from the the website called accessing Hardware from applications or something so something along those lines so what are the steps involved well first you have to from user space you have to obtain a mock port that you use to communicate with the kernel then you have to create a matching dictionary that's very similar to the matching dictionary we showed in the demo of of the personality all the nth and the same rules apply to this matching dictionary you must fill in fields from either the device descriptor or the interface descriptor based on the weather your driver is looking to to be a class type driver or a vendor specific type driver so you you add these fields by adding qualifications to this matching dictionary and then you ask IO kit to give you a kernel iterator of kernel objects that match your particular dictionary so how do we obtain the master port well the the Interfaith the API is defined in mock H and it's just a call to IO master port when you're done you should be allocate that port to tell i/o kit you're done using it so how do I create the matching dictionary well it depends on whether you're looking for an i/o USB device or an i/o USB interface in the device case you you ask for an i/o service matching dictionary with the device class name if you're looking for an interface you asked for the dictionary with the interface class name then you add qualifications to the matching dictionary again these are the qualifications we showed a table earlier they're from the section 3.10 of the USB come class specification and in the current shipping version of of USB the i/o USB family the one in 1003 and in 1002 in 1001 and 1002 this matching dictionary what that means is that if you want to match say the second line which was ID vendor and ID product you must include both of those fields in your matching dictionary and you may not include any additional fields in your matching dictionary such as the device class or the device subclass or else your matching dictionary will fail so and you also need to be aware when creating these matching dictionaries of the different rules too in this section of the common class specification for matching against IO USB device objects and IO USB interface objects once you've added the qualifications to your matching dictionary the next step is to get a list of services within the kernel these are the kernel objects that are that are subclasses of i/o service like every kernel object IO kit kernel object is and you and an i/o kit will return to you an iterator of all of these services you then can access these services one at a time to determine if it is in fact the object that you wish to control so to use this IO this IO service T that I you back through this iterator you then can call IO create plug-in interface for service this is the call that instantiates the pair of objects the device interface or interface interface on the user side with the device user client or the interface user client on the kernel side this call creates those two objects sets up that communication channel and allows you to then communicate with the object that you want to communicate with so if you were creating a user client if you were looking for a user client for the USB device object you would use the first call here with ki o USB device user client type ID and if you were interested in the interface instead you would do ki o USB interface user client type ID these these big long constant names by the way are defined in IO USB live H once you have this IO CF plug-in interface this is actually a very small interface that that does not quite yet represent the the device or interface you're looking for you have to then call a function called query interface to say I'm looking for this particular type of interface whether it's the device interface or the interface interface now let's say I have an i/o USB device interface what can I do with it well this would be the pieces of a standard initialization sequence you would open the device you would then get a pointer to the configuration descriptors for this device you might then find the configuration value out of one of those configuration descriptors and call set configuration and then once you've called set configuration you would be interested mostly in in looking at the different interfaces that have now appeared on this device so you would create an interface iterator and this would in turn return to you io service T tokens for the various interfaces attached to this device and you could create interface interface for each of them to to find the one you're looking for when you're done of course you should close that USB device and release the interface so what now that I have an i/o USB interface interface what might I do with it well you would call USB interface open to obtain exclusive access to this interface you could then find out how many endpoints this interface has in it you might choose an alternate interface if you know that there is one you might get the properties of each of the pipes in this interface you could then call Reed pipe and right pipe to read and write data across this pipe to the endpoint you're interested in and when you're done you would close the interface close the i/o USB interface and then release the interface interface how do you do a synchronous i/o from user space you don't need to be careful about doing synchronous i/o versus asynchronous i/o the because the user space threads are never running on the work loop it's okay to do synchronous i/o all the time if however you want to do asynchronous i/o then you need to take your interface whether it's the device interface or the interface interface and create an async event source and add that event source to your CF run loop and documentation for CF run loop is in CF run Luke H and you would then call CF run loop run and your your event source and possibly more than one event source would then get processed by that CF run loop calling back the callback routines for your asynchronous calls again the the USB specific header file in the i/o kit framework is listed above it as I said it's in the i/o kit framework and it provides the API for both the device interface and the interface interface now how do you package this up if you're writing a user mode driver we really discourage applications from talking directly to USB devices although it certainly can be done using this mechanism but how do i package this up well typically you would package this as either a mock o CF bundle or Ora see a plug in you may recognize this slide from the i/o kit overview the currently there's a problem with CFM apps talking directly to CF plugins so you're you you would package it up as a mock o CF bundle which could be communicated from the CFM app and then your bundle would talk to our CF plug-in which represents the device interface or the interface interface if it if the Mac if the app in question is a mock o app instead of a CFM app it can talk directly to either your cf plug-in or our CF plug-in so you could create a plug-in that was sort of a layer between because one CF plug-in can certainly talk to another CF plug-in so that's how you package this in user land and get it delivered it can also be for example a daemon type process that's always sitting around waiting to be notified when a particular USB device or USB interface appears and can then start using that device or interface as it sees fit ok now we're going to switch to the demo machines and we're going to do a little bit of debugging a little bit of a demo on how to debug we're going to show you first how easy it is to debug a user mode driver or application and then we're going to actually attempt to do a two machine debugging for kernel mode driver using both machines do you have very point okay so here is my userspace driver it's actually just written as a as a UNIX tool so of course it has the main routine and and what I'm gonna do here is I'm gonna go ahead and and just put a breakpoint right there I'm gonna go ahead and rebuild the driver just to make sure that it's built okay okay and then I'm going to hit the debug can to show you that Here I am I'm at this line of code I'm creating my master port I have all my arguments up here this is the project builder interface to gdb for those of you who haven't seen it so I create my master port I create my let me scroll this up a little bit I create the matching dictionary I'm saying I'm looking for an IO USB device I'm gonna go ahead and plug the device in let's see I need to can actually see where is it yeah I can actually show you the console the gdb console and the printf statements that we stick in here you know appear on that console so I create the matching dictionary I add the property for the vendor name and the product name which are really the vendor ID and Product ID someone has filed a bug with us that those are terrible constant names and and I agree I create a notification for the for this particular type of device and at this point I think I actually will have been notified about it because I've already plugged it in so what I'm going to do is I'm going to go into my notification routine and I'm going to set a breakpoint at the call to the to create the plug-in interface and I'm going to continue okay so now I'm at the create plug-in interface for service and I'm going to go ahead and bring up the i/o registry Explorer it's at the cool okay so this is the device I just plugged in it's called USB toca and that's the name string that's inside the device and what we can see here is that there is no user client attached to this device yet this user client an it object is used to tell i/o kit which object to create when it's when someone asks for a user client so now if I go back to my debug statement here and create the plug-in interface for service now if I go back to i/o well it should have created it hold on oh I need to do the query interface that's gotta be what it is well looks like IO registries not okay there's the device user client I don't know why this version of IO registry is not updating but there's the IO device user client which is the kernel side object of the device interface pair so that I am now I now have a user mode application communicating with this IO USB device object so then what I will do is I will I will call get the vendor get the product and get the release number we can see that the vendor if I look in my my variables here the vendor is 1209 which is what I expected and the product is 768 which is also what I expected I do a little test to make sure it's what I expected and it is and so I open this device using the USB device open function then I'm going to configure this device and so I'm I'm going to first determine how many configurations there are and I can see that there's one configuration and I'm going to then get the configuration descriptor pointer for this configuration and here is the the configuration description pointer the configuration value that I'm going to end up calling set configuration with is a 1 and I call set configuration and now I ochio registry explorer does update and when I go and I look in fact now I have an interface associated with this device attached to this device that interface appeared in the kernel because I made a set configuration call but I didn't make it directly in the kernel I made it from user space and it went through the device interface and and created the configuration so that's pretty much the end of this user debugging demo but you can see that it's pretty simple to to debug this using project builder in gdb because you're in user space and you're not trying to you know step through code in the kernel so that's the user space driver demo again it's much easier so we recommend that that's where you put your driver however in the case where you really need to be doing a kernel-mode driver for example a a mouse driver keyboard driver mass storage driver and so forth we're gonna show you the techniques that you need to use to do two machine debugging with gdb this stuff is defined in an i/o kit document debugging an i/o kit driver or something like that that that goes through these steps but we're just going to show you that in fact they they it can be done so the first step that you need to do when trying to set up a two machine debugging environment is you have to know the hardware Ethernet address of the other machine you could look at the ARP table for those of you who are UNIX people and you say and the first thing you got to do is you have to delete the ARP entry for the other machine so I'm gonna do that then you have to create a static entry for that IP address for that ethernet that IP address to that Hardware Ethernet address all of this again is documented in the debugging kernel driver document now that I have that connection it's a permanent connection in my ARP table which you can see and so now if I have the driver over here cousin we have I can talk to it so can we split the screen and put demo two on one of them okay he's going to load a driver and we have a debug statement in the in the start method of this driver he's gonna plug it in and he's frozen because he's got this debug statement so okay so I'm going to load gdb and then I'm going to say target remote KDP this is in that document again and then I'm going to attach to this other machine okay I am now connected to that other machine I can do a back trace and I can see that I'm in a debugger call but I need the symbols for my for my driver so I will use a command called show all kay mods which shows me all of the kernel modules that are loaded on this machine so that would be that one and and then I'm going to say okay oops here's the address of my driver and now I need to create symbols for this driver which I built on this machine so so I do K mod Sims and because it is dependent on the IOUs be family and I need to know the address of the IOUs be family so that's in here as well so you can see that debugging is somewhat more painful when in the kernel

  • hole

okay I gotta get the address again okay now I have a simple file for this and so I add this symbol file to my to my gdb session and now if I do a back trace I can actually see all my line numbers and and it didn't put it in well okay so we are out of time basically I can then I attach to this thing I can go ahead and continue so this machine is now up and running again you can see by that and he can unplug the device and oh it kernel panic well we were actually expecting that we did that on purpose and if you look at the back trace you can actually see where in the drive where it terminated and if I had the symbols working properly which we're out of time to do we put a line of code in there the dereference null and we did that on purpose to try to debug it but again we do need to answer some questions so we've taken five minutes of question-and-answer time to do this but that's the process you have to go through to do two machine debugging so it's somewhat more painful and we recommend doing user mode whenever you can okay [Applause] you