Search This Blog

Thursday, October 16, 2014

PowerShell commands to configure Generation 2 VM kernel debug

Generation 2 VM has UEFI rather than BIOS. This means that secure boot is enabled by default but kernel debugging and secure boot are mutually exclusive.
Therefore, we will need to disable that first. Generation 2 VM still supports serial ports. We can set up serial ports for debugging again through PowerShell.

Here are two PowerShell commands to accomplish this:

 PS C:\> Set-VMFirmware -VMName testvm -EnableSecureBoot Off  
 PS C:\> Set-VMComPort testvm 1 \\.\pipe\vmdebug  

Switching to a different group - How I prepared for it.

I have been working in my current team for about three years so far and wanted to change the team to do different type of work. While I enjoyed debugging some hard problems and coming up with the fix, I have been wanting to consistently work on certain code base to learn the technology and deepen domain knowledge. Hence, I reached out those who I used to work with to gather some input/advice before I start to look around and today's blog is about what I have learned/gathered during this process.
First, do I really want a change?
One person whom I spoke to said it very clearly. He said that he could have made more impact on the product if he had stayed in my current team but he knew that he's not learning new technologies as much as he wanted in the current team. As such, he made a move and that has challenged him a lot for the past one year and felt that he grew so much. His new role/work is involved in big data/scale out work which helps him to be exposed to the latest hot topics and he's enjoying what he's doing. He mentioned that the process has been somewhat painful but that was intentional and he's glad that he made the move. As I was listening to him, I felt that I am in the similar situation that he was in a year ago and I want to have the similar changes in my own career. After that, I reached out to few more guys that I used to work with to gather some more information on how they found their new jobs. This helped me to what to look for and what's ahead when looking for jobs. With this, I started to look around opportunities inside the company mostly and started to send out my application with my resume based on HR job lists.

Second, what should I prepare for the interview?
You might say, "Interview?" Yes, we may still need to go through the interview process even if we change jobs inside the company. I learned that if I change jobs within the same group, I don't have to go through the interview but if I want to switch to different group, the interview process is required. As you guessed, preparing for the interview is not an easy task in computer science field. You will have to grab those programming algorithm books that I used in school and try to brush up your problem solving skills. Sometimes I wonder if this is really necessary in that we may never get to use some of these algorithms/data structures. Yet, that's the way it is so you will need to adapt to the system for the time being. :) Thanks to my friends, I came to know two very useful resources to prepare the interview and they are leetcode.com and EPI(Element of Programming Interview).

These two helped me immensely to be ready for technical interviews so let me describe these two a bit more in detail. leetcode.com is very helpful in that it has online judge site where you can solve the problems and submit your code to run the solution against test cases to see if your solution is correct and efficient. On top of that, you can also peek into other people's solution in discuss forum to see if there is any better solution. From this site I was able to check if my solution is correct and also learned how others solved the problem to enhance my solutions. It has about 150 problems to solve and you will surely learn much and confirm your answer via this web site to get ready for the interview.
Now, let me talk about EPI. In my opinion, EPI is one of the best books out there to prepare for the technical interview. It has a lot of questions and these questions are not easy but through these questions I felt that I am getting ready for the interview. It has questions that I never thought about so that helps you to think about such problems so that your brain gets exercised. In fact, some of questions that I studied from this book came up during the interview so that was very helpful.
I know that there are many more problems out there and I have heard from friends that some other companies tend to ask more difficult questions than what I have found from the above two resources. However, I think that these two have to be the base to start with so I highly recommend them!

Additionally, I would like to emphasize the amount of time you want to spend to prepare. Personally, it is very helpful if you can concentrate in studying the above two within short period of time so that you do not lose the context. It might be difficult to find time to study but I feel that you should treat this preparation as part of your job and take it seriously. Probably, it is a good idea to study for about three to four hours each day and seven to eight hours during weekends so that you can make significant process.


Third, which company/team to choose?
I did not have a lot of choices as I had four different interviews total. While going through the interview and getting to know each team/company, it became clear to me which team/company I would like to join. I believe that the interview process is not just one sided. It is not just the interviewee trying to impress upon the interviewer and pass the interview. It is also the interview's responsibility to sell their team/company so that the interviewee would like to come and work with them. I interacted with four different team/company, I felt comfortable with one particular team and decided to join that team. To be clear, I did not get offers from all these four places I had an interview with.

Lastly and perhaps most importantly, I would like to mention the importance of networking.
Making a career change is not an easy task but I have received a lot of advice and tips from friends/ex teammates that I worked with. I feel that keeping these relationships well is very important aspect of our career and as such, my advice to everyone is to reach out to friends/ex teammates for advice and you will be surprised how much you can learn from your peers to succeed in making career change. So if you are thinking of making changes in your career, send an email to your friend for lunch and ask them for their input.

All the best!

Saturday, January 18, 2014

Visual Studio makes it real easy to write drivers

I have heard sometime ago that visual studio now fully supports driver development. Years ago, I found some web resource to modify visual studio settings to make this happen but now that it officially supports driver development, I decided to give it a try.

In order to do this, you will need to install WDK from this msdn web site. Once you install WDK, start up Visual Studio and you will find Driver project when you start new project.
Not just that! In Visual Studio, you can even deploy your own driver to the remote computer!

MSDN also provides some hello world driver to help you to jump start.
Before deploying make sure to enable testsigning on remote computer and restart the remote computer.

However. if you want to do it manually, you will have to first install test certificate and after that right click inf file and click 'install'. That will install and start up your driver.

In case you have trouble installing driver, please check setupapi.dev.log file under C:\Windows\inf folder. If you have to debug your driver, then windbg is your friend.

Thursday, December 26, 2013

Enabling PowerShell remoting

I am experimenting PowerShell remoting lately and wanted to share simple tip to enable remoting.
To enable remoting, you will want to run 'Enable-PsRemoting' cmdlet and once you run it, it asks you several questions to which you will probably want to answer 'yes'. If you want to skip this, you can run 'Enable-PsRemoting -force' and that skips question steps.

Once you have the machine ready, by default it only allows admin to execute the script so you might want to add yourself so you can execute commands from remote computer.
To add yourself, run 'Set-PSSessionConfiguration Microsoft.PowerShell -ShowSecurityDescriptorUI' cmdlet and UI will pop up and you can use that to add yourself.

Now that you have enabled remoting, let's give it a try:

PS C:\Users\ilhoye> invoke-command -computer localhost -scriptblock {ps | select -first 5 | ft}

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    124      11     2368       6068    46            2192 Acmengine
    890      42    16560      44128   150            3416 CcmExec
     46       7     1820       5140    57     0.19    532 conhost
     46       7     1844       5184    57            1664 conhost
     46       7     1824       5168    57     0.23   2844 conhost

Finally, if you still have a trouble setting up remoting, a good place to start debugging is to run 'get-help about_Remote_Troubleshooting'. This has detailed information on most issues you might encounter.


Friday, November 15, 2013

PCI Config Space with windbg

I've been working on some PCI issue and as a result I learned a bit about PCI configuration stuff. Let me summarize few things about PCI with respect to configuration.

A processor is not capable of directly accessing these config space to read from or write to.
Instead, Root complex knows how to do this when a processor makes either IO or memory access.
For example, when processor attempts to read from config space, it will try to read from certain memory-mapped IO address. This request is latched to PCI root complex which then decodes the address and figures out whether it needs to re-route the packet to appropriate secondary bus.
While the packet is in transit, its type is set to TYPE 1 but once it reaches to PCI bridge where its one of connected bus is destination bus, it changes its type to be TYPE 0.

As mentioned, we can access config space either by IO port or memory-mapped IO. To make an access via IO port, we use 0xCF8 (address port) and 0xCFC (data port).
To view if these are allocated, we can use windbg to see.
 0: kd> !arbiter 1  
 DEVNODE fffffa8009782cb0 (HTREE\ROOT\0)  
  Port Arbiter "RootPort" at fffff802e555c5a0  
   Allocated ranges:  
    0000000000000000 - 00000000000003af    
     0000000000000000 - 00000000000003af SC  fffffa80097d1d30 (pci)  
     0000000000000000 - 00000000000003af SC  fffffa80097d1d30 (pci)  
     0000000000000000 - 000000000000000f CB  fffffa8009789a50   
     0000000000000020 - 0000000000000021 CB  fffffa8009789a50   
     0000000000000040 - 0000000000000043 CB  fffffa8009789a50   
     0000000000000048 - 000000000000004b CB  fffffa8009789a50   
     0000000000000070 - 0000000000000071 CB  fffffa8009789a50   
     0000000000000080 - 000000000000008f CB  fffffa8009789a50   
     0000000000000092 - 0000000000000092 CB  fffffa8009789a50   
     00000000000000a0 - 00000000000000a1 CB  fffffa8009789a50   
     00000000000000c0 - 00000000000000cf CB  fffffa8009789a50   
     00000000000000f0 - 00000000000000ff CB  fffffa8009789a50   
    00000000000003b0 - 00000000000003df S   fffffa80097d1d30 (pci)  
    00000000000003e0 - 0000000000000cf7 S   fffffa80097d1d30 (pci)  
    0000000000000cf8 - 0000000000000cff  B  fffffa8009789a50   
    0000000000000d00 - 0000000000000fff S   fffffa80097d1d30 (pci)  
    0000000000001000 - 000000000000efff S   fffffa80097d1d30 (pci)  
   Possible allocation:  
    < none >  

We see that we have allocated resource between cf8 and cff under RootPort. Let us run a couple more debugger commands to connect again between root port and resources.
 0: kd> !devobj fffffa8009789a50  
 Device object (fffffa8009789a50) is for:  
  00000010 \Driver\PnpManager DriverObject fffffa80097560f0  
 Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040  
 Dacl fffff9a10010dd91 DevExt fffffa8009789ba0 DevObjExt fffffa8009789bb0 DevNode fffffa8009749010   
 ExtensionFlags (0x00000800) DOE_DEFAULT_SD_PRESENT  
 Characteristics (0x00000080) FILE_AUTOGENERATED_DEVICE_NAME  
 AttachedDevice (Upper) fffffa80097a34b0 \Driver\ACPI_HAL  
 Device queue is not busy.  
 0: kd> !devnode fffffa8009749010 6  
 DevNode 0xfffffa8009749010 for PDO 0xfffffa8009789a50  
  Parent 0xfffffa8009782cb0  Sibling 0xfffffa800979bd30  Child 0xfffffa800970b010    
  InstancePath is "ROOT\ACPI_HAL\0000"  
  State = DeviceNodeStarted (0x308)  
  Previous State = DeviceNodeEnumerateCompletion (0x30d)  
  StateHistory[05] = DeviceNodeEnumerateCompletion (0x30d)  
  StateHistory[04] = DeviceNodeEnumeratePending (0x30c)  
  StateHistory[03] = DeviceNodeStarted (0x308)  
 [snip]  
  StateHistory[08] = Unknown State (0x0)  
  StateHistory[07] = Unknown State (0x0)  
  StateHistory[06] = Unknown State (0x0)  
  Flags (0x0c0001f5) DNF_MADEUP, DNF_HAL_NODE,   
            DNF_ENUMERATED, DNF_IDS_QUERIED,   
            DNF_HAS_BOOT_CONFIG, DNF_BOOT_CONFIG_RESERVED,   
            DNF_NO_RESOURCE_REQUIRED, DNF_NO_LOWER_DEVICE_FILTERS,   
            DNF_NO_LOWER_CLASS_FILTERS  
  DisableableDepends = 1 (from children)  
  BootResourcesList at 0xfffff8a000069ae0 Version 0.0 Interface 0 Bus #0  
   Entry 0 - Interrupt (0x2) Driver Exclusive (0x2)  
    Flags (0000) - LEVEL_SENSITIVE   
    Level 0, Vector 0, Group 0, Affinity 0xff  
    Range starts at 0x92 for 0x1 bytes  
   Entry 56 - Port (0x1) Driver Exclusive (0x2)  
    Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE   
    Range starts at 0xa0 for 0x2 bytes  
 [snip]  
    Range starts at 0xf0 for 0x10 bytes  
   Entry 59 - Port (0x1) Driver Exclusive (0x2)  
    Flags (0x11) - PORT_MEMORY PORT_IO 16_BIT_DECODE   
    Range starts at 0xcf8 for 0x8 bytes  
   Entry 60 - Memory (0x3) Driver Exclusive (0x2)  
    Flags (0000) - READ_WRITE   
    Range starts at 0x00000000fec00000 for 0x400 bytes  
 [snip]  

So we can see how 0xCF8 and 0xCFC ports are allocated under Root Port.
If you want to see if we ever use these ports to access config space, we can set a brekpoint but these are legacy way so most likely we won't hit the breakpoint this case.
At any rate, here is how you set the breakpoint:
 0: kd> ba i4 0xcfc  
 0: kd> bl  
  1 e 00000000`00000cfc i 4 0001 (0001)  

Wednesday, October 30, 2013

Some simple change to prevent future problem

This sounds so basic but I think we always want to have a second look on our code to see if we can improve the code. For instance, I had a piece of code that takes index as input and return the value from the array. The following is hypothetical example.

 int map_func(ULONG index)  
 {  
   assert(index < max);  
   return array[index];  
 }  

When I call this function, I make sure that index is within the range. But my code interfaces with other code and as the time goes on, the code becomes pretty complicated that I had a case where input 'index' was out of range and hence, the program crashed.
So I fixed that and after a few months later, the similar issue occurred. Only then, I realized that I should have changed 'assert' to the check that would survive even in free build.
Here is the new change.
 int map_func(ULONG index)  
 {  
   if (index >= max) {  
     assert(FALSE);  
     log("error occurred: %d\n", index);  
     return -1;  
   }  
   return array[index];  
 }  

Now, I can avoid program crash in free build and also have the assert in checked build. I know this is such a simple case but I only came up with this resolution when I stopped and thought about the fix one more time.

I think I will need this stop and think moment for all my works.

Saturday, November 10, 2012

Toaster device - installing wdm driver

I have been trying to understand how toaster wdm device works and apparently I spent so much time trying to install these drivers on my VM. First of all, its readme file is helpful but I found it lacking in some of its explanations. At first, I used devcon.exe to install bus driver but I bumped into a couple of issues so I could not install bus driver properly.
I searched online and found this msdn page where on the bottom it explains how to install toaster bus driver.

So that was helpful and on to the next issue: function driver. I could start up toaster by using enum.exe but it could not find some files that function driver was not installed. The message was not really helpful in that it does not say which files missing and part of it is that I do not fully understand what's needed for this install to happen. I could have spent time understanding installing package requirement but my goal was to understand Power management using this toaster before anything else.
Then, again from online I learned that I can look at setupapi.dev.log for more clue. By the way, this file is located in C:\Windows\inf directory.
Here is the error message I found from log file:
!!!  flq:                               Error installing file (0x00000002)
!!!  flq:                               Error 2: The system cannot find the file specified.
!    flq:                                    SourceFile   - 'c:\work\toaster\device\amd64\tostrco2.dll'
!    flq:                                    TargetFile   - 'C:\Users\ILHOYE~1.RED\AppData\Local\Temp\{6d5b7b46-959d-0823-c45e-094dc5a9816c}\amd64\tostrco2.dll'


By now, it is clear that I am missing tostrco2.dll. I don't know what file is for but I know that I need it. So I grabbed this from WDK and after that I could install toaster function driver. Now, I can happily debug toaster to understand the code flow.

How about traces? Is there any traces available with toaster driver? Yes, many of kernel drivers use either ETW or WPP tracing and hence by providing appropriate information you can turn on/off debug messages. These messages can be captured and saved to the file or you can actually see them if you have the debugger attached to your target machine/VM. In fact, toaster driver readme file describes the steps to do it but let me repeat that here. First of all, start the trace session by executing the following command where toaster.ctl contains "C56386BD-7C67-4264-B8D9-C4A53B93CBEB toaster"

c:\temp>tracelog -start toaster -rt -kd -ft 1 -guid toaster.ctl -flags 0xff

After that, in the kernel debugger you need to set the wmi path to refer to the TMF file location. What's TMF file? It is the file that contains information to translate the debug message to human readable strings. You can generate tmf file from pdb file by running 'tracepdb -f toaster.pdb' Here is how to set the path and enable debugging message.

kd>!wmitrace.searchpath + path_of_TMF_files
kd> !wmitrace.strdump
(WmiTracing)StrDump Generic
  LoggerContext Array @ 0x80BF1760 [64 Elements]
    Logger Id  2 @ 0x820C5000 Named 'MSDTC_TRACE_SESSION'
    Logger Id  3 @ 0x81AAF000 Named 'toaster'

kd> !wmitrace.enable 3
With that, you should be able to see the trace messages. Of course, you can always set the breakpoint where you are interested in to look into more details but knowing how to leverage existing traces should be helpful.

For toaster bus driver, if you want to see the debug messages, you will need to use chk build and use dbgview to enable kernel verbose debugging. However, once you turn on kernel verbose debugging, it will generate all sorts of debugging messages that you may not care about. Toaster bus driver uses DbgPrint for debug messages and that is essentially same as the following.

DbgPrintEx ( DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, Format, arguments )

Therefore, we need to enable mask and level according to our mask and level. We can do this either updating registry or updating values via kernel debugger. For more information, please refer to MSDN page 'Reading and Filtering Debugging Messages' that describes how to enable certain component.