Drivers For 64-Bit Drivers For 64-Bit Windows Windows ® ® Nar Ganapathy Nar Ganapathy Software Design Engineer Software Design Engineer Windows NT Windows NT ® ® Base Systems Base Systems Microsoft Corporation Microsoft Corporation
Drivers For 64-Bit WindowsDrivers For 64-Bit Windows®®
Nar GanapathyNar GanapathySoftware Design EngineerSoftware Design EngineerWindows NTWindows NT®® Base Systems Base SystemsMicrosoft CorporationMicrosoft Corporation
AgendaAgenda What is 64-bit WindowsWhat is 64-bit Windows Programming modelProgramming model Porting guidelinesPorting guidelines Programming issuesProgramming issues
64-Bit Windows 2000 Goals64-Bit Windows 2000 Goals Porting from Win32Porting from Win32®® to Win64 to Win64
should be simpleshould be simple A single source code base for Win32 A single source code base for Win32
and Win64and Win64 Enable existing applications to scale Enable existing applications to scale
to enterprise capacitiesto enterprise capacities Enable new designs that use huge Enable new designs that use huge
address space and memoryaddress space and memory Support existing 32-bit applicationsSupport existing 32-bit applications
32-bit device drivers not supported32-bit device drivers not supported
What Is 64-Bit Version Of What Is 64-Bit Version Of Windows 2000?Windows 2000? 64-Bit Windows is an evolution of 64-Bit Windows is an evolution of
the Windows programming model the Windows programming model and APIsand APIs
LLP64 modelLLP64 model Pointers are expanded to 64 bitsPointers are expanded to 64 bits Memory allocation sizes are 64 bitsMemory allocation sizes are 64 bits Longs and ints are 32 bitsLongs and ints are 32 bits
Win64 Programming ModelWin64 Programming Model Uses the same Win32 DDIs/APIsUses the same Win32 DDIs/APIs Adds new explicitly sized typesAdds new explicitly sized types Adds new integral types that match Adds new integral types that match
the precision of a pointerthe precision of a pointer Almost all Win32 32-bit data types Almost all Win32 32-bit data types
remain 32-bitsremain 32-bits E.g., size of ULONG is still 32 bits E.g., size of ULONG is still 32 bits
under Win64under Win64 Pointers are 64-bitsPointers are 64-bits
Win64 Programming ModelWin64 Programming Model Items expanded to 64 bitsItems expanded to 64 bits
Length for most memory allocationsLength for most memory allocations CPU maskCPU mask
UnchangedUnchanged Length for I/O operationsLength for I/O operations Unicode string lengthsUnicode string lengths
Win64 Data TypesWin64 Data TypesTYPE NAMETYPE NAME What It isWhat It isLONG32, INT32LONG32, INT32 32 bit signed32 bit signed
LONG64, INT64LONG64, INT64 64 bit signed64 bit signed
ULONG32,UINT32ULONG32,UINT32,DWORD32,DWORD32
32 bit unsigned32 bit unsigned
ULONG64,UINT64ULONG64,UINT64,DWORD64,DWORD64
64 bit unsigned64 bit unsigned
Win64 Data Types Win64 Data Types ContinuedContinued
TYPE NAMETYPE NAME What it isWhat it is
INT_PTR,LONG_PTRINT_PTR,LONG_PTR Signed Int,Signed Int,Pointer precisionPointer precision
UINT_PTR,UINT_PTR,ULONG_PTR, ULONG_PTR, DWORD_PTRDWORD_PTR
Unsigned Int,Unsigned Int,Pointer precisionPointer precision
SIZE_TSIZE_T Unsigned count, Pointer Unsigned count, Pointer precisionprecision
SSIZE_TSSIZE_T Signed count,Signed count,Pointer precisionPointer precision
Win64 Porting GuidelinesWin64 Porting Guidelines Use Win64 safe data typesUse Win64 safe data types Examine all pointer usage, especially Examine all pointer usage, especially
pointer arithmeticpointer arithmetic Two major porting topicsTwo major porting topics
Driver specific issues (e.g., IOCTLs, DMA)Driver specific issues (e.g., IOCTLs, DMA) Programming issuesProgramming issues
Memory Management (IA64)Memory Management (IA64) User addresses range from 0x10000 – User addresses range from 0x10000 –
0x000006FBFFFEFFFF 0x000006FBFFFEFFFF One terabyte system cacheOne terabyte system cache Sixteen gigabyte HyperSpaceSixteen gigabyte HyperSpace 128 gigabyte paged pool128 gigabyte paged pool 128 gigabyte System address space for 128 gigabyte System address space for
kernel threads, etc.kernel threads, etc. 128 gigabyte non-paged pool128 gigabyte non-paged pool Physical memory addresses are 64 bitsPhysical memory addresses are 64 bits
WOW64WOW64 Runs Windows NT x86 binariesRuns Windows NT x86 binaries No support for mixing of x86 and IA-64 No support for mixing of x86 and IA-64
code within a processcode within a process User/kernel transitions are thunked to User/kernel transitions are thunked to
account for structure differences and account for structure differences and transition between instruction setstransition between instruction sets
Only a few dlls are thunked: ntdll.dll Only a few dlls are thunked: ntdll.dll user.dll, gdi.dll plus a set of LPC callsuser.dll, gdi.dll plus a set of LPC calls
The rest of the dlls are stock x86 binaries The rest of the dlls are stock x86 binaries copied from the release sharescopied from the release shares
Driver Specific IssuesDriver Specific Issues Drivers need to support Plug and Play Drivers need to support Plug and Play
and Power Managementand Power Management I/O request length is limited to 32 bitsI/O request length is limited to 32 bits 32-bit devices will be double buffered 32-bit devices will be double buffered
for DMA transfersfor DMA transfers Some drivers will need to support 32- Some drivers will need to support 32-
and 64-bit versions of IOCTL commandand 64-bit versions of IOCTL command
Support 32-Bit IOCTLSSupport 32-Bit IOCTLS IOCTL structures that contain pointer IOCTL structures that contain pointer
dependent types have different sizes dependent types have different sizes in 64-bit and 32-bit applicationsin 64-bit and 32-bit applications
Driver has to distinguish between Driver has to distinguish between Ioctls issued from 32-bit or Ioctls issued from 32-bit or 64-bit threads64-bit threads
Driver validates the input or output Driver validates the input or output buffer lengths based on the issuer’s buffer lengths based on the issuer’s bit widthbit width
Supporting 32-Bit IOCTLSupporting 32-Bit IOCTL Three possible solutionsThree possible solutions
Avoid having pointer types in Avoid having pointer types in IOCTL structuresIOCTL structures
Use the API IoIs32bitProcess()Use the API IoIs32bitProcess() Use a new bit in the Function code field Use a new bit in the Function code field
of the IOCTL code for 64-bit callersof the IOCTL code for 64-bit callers
32 And 64-Bit IOCTL 32 And 64-Bit IOCTL ExampleExample IOCTL structure in header fileIOCTL structure in header file
typedef struct _IOCTL_PARAMETERS {typedef struct _IOCTL_PARAMETERS {
PVOID Addr;PVOID Addr;
SIZE_T Length;SIZE_T Length;
HANDLE Handle;HANDLE Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;
32 And 64-Bit IOCTL 32 And 64-Bit IOCTL ExampleExample 32-bit IOCTL structure32-bit IOCTL structure////// This structure is defined inside the driver source code// This structure is defined inside the driver source code////typedef struct _IOCTL_PARAMETERS_32 {typedef struct _IOCTL_PARAMETERS_32 { VOID*POINTER_32 Addr;VOID*POINTER_32 Addr; INT32 Length;INT32 Length; VOID*POINTER_32 Handle;VOID*POINTER_32 Handle;} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;
32 And 64-Bit IOCTL 32 And 64-Bit IOCTL ExampleExample#ifdef _WIN64#ifdef _WIN64case IOCTL_REGISTER:case IOCTL_REGISTER:if (IoIs32bitProcess(Irp)) {if (IoIs32bitProcess(Irp)) { /* If this is a 32 bit process */ /* If this is a 32 bit process */ params32 = (PIOCTL_PARAMETERS_32) params32 = (PIOCTL_PARAMETERS_32) (Irp->AssociatedIrp.SystemBuffer); (Irp->AssociatedIrp.SystemBuffer); if(irpSp->Parameters.DeviceIoControl.InputBufferLength < if(irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PIOCTL_PARAMETERS_32)) { sizeof(PIOCTL_PARAMETERS_32)) { status = status = STATUS_INVALID_PARAMETER; STATUS_INVALID_PARAMETER; } } else {else { LocalParam.Addr = params32->Addr; LocalParam.Addr = params32->Addr; LocalParam.Handle = params32->Handle; LocalParam.Handle = params32->Handle; LocalParam.Length = params32->Length;LocalParam.Length = params32->Length; /* Handle the ioctl here *//* Handle the ioctl here */
status = STATUS_SUCCESS; status = STATUS_SUCCESS; Irp-Irp->IoStatus.Information = sizeof(IOCTL_PARAMETERS); >IoStatus.Information = sizeof(IOCTL_PARAMETERS); }}
32 And 64-Bit IOCTL 32 And 64-Bit IOCTL ExampleExample} else { /* 64bit process IOCTL */} else { /* 64bit process IOCTL */ params = (PIOCTL_PARAMETERS)params = (PIOCTL_PARAMETERS) (Irp->AssociatedIrp.SystemBuffer); (Irp->AssociatedIrp.SystemBuffer); if (irpSp->Parameters.DeviceIoControl.InputBufferLengthif (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IOCTL_PARAMETERS)) { < sizeof(IOCTL_PARAMETERS)) { status = STATUS_INVALID_PARAMETER; status = STATUS_INVALID_PARAMETER; } } else { else {
RtlCopyMemory(&LocalParam, params, RtlCopyMemory(&LocalParam, params, sizeof(IOCTL_PARAMETERS)); sizeof(IOCTL_PARAMETERS));
/* Handle the ioctl here *//* Handle the ioctl here */ status = STATUS_SUCCESS;status = STATUS_SUCCESS;
}}Irp->IoStatus.Information = sizeof(IOCTL_PARAMETERS);Irp->IoStatus.Information = sizeof(IOCTL_PARAMETERS);
}}break; break;
Use New IOCTL CodeUse New IOCTL Code Use bit in function field to indicate Use bit in function field to indicate
64-bit IOCTL64-bit IOCTL Current IOCTL codes have four fieldsCurrent IOCTL codes have four fields
New IOCTL code has one extra bit for 64 New IOCTL code has one extra bit for 64 bitbit
Device Type Device Type (16)(16)
Access Access (2)(2)
Function Function (12)(12)
Method Method (2)(2)
Device Device Type (16)Type (16)
Access Access (2)(2)
64 bit 64 bit (1)(1)
Function Function (11)(11)
Method Method (2)(2)
DMA APIsDMA APIs Drivers should use PHYSICAL_ADDRESS Drivers should use PHYSICAL_ADDRESS
typedef to access physical addresses typedef to access physical addresses (64 bits long)(64 bits long)
Driver must treat all 64 bits as a Valid Driver must treat all 64 bits as a Valid Physical Address, do not ignore top 32 bitsPhysical Address, do not ignore top 32 bits
Drivers must use the Windows DMA APIsDrivers must use the Windows DMA APIs IoAllocateAdapter, IoAllocateAdapter,
IoAllocateAdapterChannel,IoMapTransfer,etc. IoAllocateAdapterChannel,IoMapTransfer,etc. Use new scatter/gather DMA APIsUse new scatter/gather DMA APIs Devices with 64-bit addressing capability will Devices with 64-bit addressing capability will
significantly improve performancesignificantly improve performance
Programming IssuesProgramming Issues Polymorphic Data usagePolymorphic Data usage Miscellaneous cleanupMiscellaneous cleanup Alignment issuesAlignment issues
Polymorphic Data UsagePolymorphic Data Usage Don’t cast pointer to int, long, Don’t cast pointer to int, long,
ULONG, DWORDULONG, DWORD Use UINT_PTR and INT_PTRUse UINT_PTR and INT_PTR
ImageBase = (PVOID)ImageBase = (PVOID) ((ULONG)ImageBase | 1); ((ULONG)ImageBase | 1);
ImageBase = (PVOID)ImageBase = (PVOID) ((ULONG_PTR)ImageBase | 1); ((ULONG_PTR)ImageBase | 1);
Should be re-written asShould be re-written as
……Polymorphic Data Usage…Polymorphic Data Usage… Use PtrToUlong and PtrToLong to Use PtrToUlong and PtrToLong to
truncate pointerstruncate pointers Never cast a int or ULONG that stores a Never cast a int or ULONG that stores a
truncated pointer back to a pointertruncated pointer back to a pointer Be careful when computing buffer sizes; Be careful when computing buffer sizes;
Sizes may exceed capacity of ULONGSizes may exceed capacity of ULONG
……Polymorhpic Data UsagePolymorhpic Data Usage Be careful when calling functions Be careful when calling functions
that have pointer OUT parametersthat have pointer OUT parameters
void GetBufferAddress(OUT PULONG *ptr);void GetBufferAddress(OUT PULONG *ptr);{{
*ptr=0x1000100010001000;*ptr=0x1000100010001000;}}void foo()void foo(){{ ULONG bufAddress;ULONG bufAddress; //// // this call causes memory corruption// this call causes memory corruption //// GetBufferAddress((PULONG *)&bufAddress);GetBufferAddress((PULONG *)&bufAddress);}}
Miscellaneous CleanupMiscellaneous Cleanup -1 != 0xFFFFFFFF-1 != 0xFFFFFFFF
0xFFFFFFFF != invalid handle0xFFFFFFFF != invalid handle DWORD is always 32 bitsDWORD is always 32 bits
Look for DWORD variables used to store Look for DWORD variables used to store pointers or handlespointers or handles
Cast pointers to PCHAR for Cast pointers to PCHAR for Pointer arithmeticPointer arithmetic ptr = (PVOID) ((PCHAR) ptr + pageSize);ptr = (PVOID) ((PCHAR) ptr + pageSize);
Miscellaneous CleanupMiscellaneous Cleanup Use %Use %II to print pointers in to print pointers in
debug statementsdebug statements Addresses >= 0x80000000 are not Addresses >= 0x80000000 are not
necessarily kernel addressesnecessarily kernel addresses
AlignmentAlignment Misaligned memory references will Misaligned memory references will
raise an exception on Win64raise an exception on Win64#pragma pack (1) /* also set by /Zp switch */#pragma pack (1) /* also set by /Zp switch */struct AlignSample {struct AlignSample {
ULONG size;ULONG size;void *ptr; void *ptr;
};};void foo(void *p) {void foo(void *p) {
struct AlignSample s;struct AlignSample s;s.ptr = p;s.ptr = p; // will cause alignment fault// will cause alignment fault......
}}
AlignmentAlignment Use UNALIGNED macro to fixUse UNALIGNED macro to fix
Better solution is to put 64-bit Better solution is to put 64-bit values and pointers at the beginning values and pointers at the beginning of the structureof the structure
void foo(void *p) {void foo(void *p) {struct AlignSample s; struct AlignSample s;
*(UNALIGNED void *)&s.ptr = p; *(UNALIGNED void *)&s.ptr = p; }}
AlignmentAlignment Be cautious of any structure Be cautious of any structure
packing directivespacking directives Be especially cautious of different Be especially cautious of different
PACK levels used in the same headerPACK levels used in the same header RtlCopyMemory and memcpy will RtlCopyMemory and memcpy will
not faultnot fault
More Programming IssuesMore Programming Issues Carefully examine Carefully examine
Explicit and implicit unions Explicit and implicit unions with pointerswith pointers
Data structures stored on disk or Data structures stored on disk or exchanged with 32-bit processesexchanged with 32-bit processes
Security descriptorsSecurity descriptors Code which deals with memory Code which deals with memory
region sizesregion sizes len = ptr2 – ptr1 len = ptr2 – ptr1 len could be greater than 2^32len could be greater than 2^32
Miscellaneous Miscellaneous Programming IssuesProgramming Issues Executive handles can be truncated Executive handles can be truncated
to 32 bitto 32 bit Piecemeal size allocations:Piecemeal size allocations:
struct foo {struct foo {DWORD NumberOfPointers;DWORD NumberOfPointers;PVOID Pointers[1];PVOID Pointers[1];
} xx;} xx;Wrong:Wrong:malloc(sizeof(DWORD)+100*sizeof(PVOID));malloc(sizeof(DWORD)+100*sizeof(PVOID)); Correct:Correct:malloc(FIELD_OFFSET(struct foo,Pointers) malloc(FIELD_OFFSET(struct foo,Pointers) +100*sizeof(PVOID));+100*sizeof(PVOID));
MiscellaneousMiscellaneousProgramming IssuesProgramming Issues Be careful when using hexadecimal constants and Be careful when using hexadecimal constants and
unsigned valuesunsigned values Following assertion not true on 64 bit systemsFollowing assertion not true on 64 bit systems
~((UINT64)(PAGE_SIZE-1)) == (UINT64)~(PAGE_SIZE-1)~((UINT64)(PAGE_SIZE-1)) == (UINT64)~(PAGE_SIZE-1)PAGE_SIZE = 0x1000UL // Unsigned Long - 32 bitsPAGE_SIZE = 0x1000UL // Unsigned Long - 32 bitsPAGE_SIZE - 1 = 0x00000fff PAGE_SIZE - 1 = 0x00000fff
LHS expression:LHS expression:// Unsigned expansion // Unsigned expansion (UINT64)(PAGE_SIZE -1 ) = 0x0000000000000fff(UINT64)(PAGE_SIZE -1 ) = 0x0000000000000fff~((UINT64)(PAGE_SIZE -1 ))= 0xfffffffffffff000~((UINT64)(PAGE_SIZE -1 ))= 0xfffffffffffff000
RHS expression:RHS expression:~(PAGE_SIZE-1) = 0xfffff000~(PAGE_SIZE-1) = 0xfffff000(UINT64)(~(PAGE_SIZE - 1)) = 0x00000000fffff000(UINT64)(~(PAGE_SIZE - 1)) = 0x00000000fffff000
HenceHence~((UINT64)(PAGE_SIZE-1))!= (UINT64)(~(PAGE_SIZE-1))~((UINT64)(PAGE_SIZE-1))!= (UINT64)(~(PAGE_SIZE-1))
Miscellaneous Miscellaneous Programming IssuesProgramming Issues Be careful when using unsigned numbers Be careful when using unsigned numbers
as subscripts:as subscripts:DWORD index = 0;DWORD index = 0;CHAR *p;CHAR *p;
If (p[index – 1] == ‘0’) causes access violation on If (p[index – 1] == ‘0’) causes access violation on Win64!Win64!
On 32-bit machines:On 32-bit machines:p[index-1] == p[0xffffffff] == p[-1] p[index-1] == p[0xffffffff] == p[-1]
On 64-bit machines:On 64-bit machines:p[index-1] == p[0x00000000ffffffff] != p[-1]p[index-1] == p[0x00000000ffffffff] != p[-1]
Call To ActionCall To Action Develop Windows 2000 ready Develop Windows 2000 ready
drivers by supporting Plug and Play drivers by supporting Plug and Play and Power Managementand Power Management
Start coding using Win64 safe Start coding using Win64 safe programming practices now!programming practices now!
Use the 64-bit compiler to find Use the 64-bit compiler to find problem areasproblem areas
Make your devices address 64 bits Make your devices address 64 bits of physical memoryof physical memory
Additional InformationAdditional Information Read “Getting Ready for 64-bit Read “Getting Ready for 64-bit
Windows” porting guide on Windows” porting guide on Windows 2000 SDKWindows 2000 SDK
Other information available at Other information available at http://www.http://www.microsoftmicrosoft.com/windows2000/guide/platform/strate.com/windows2000/guide/platform/strategic/64bit.aspgic/64bit.asp