Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

nec98.h File Reference

Go to the source code of this file.

Classes

struct  _DMA_PAGE
struct  _DMA_CHANNEL_STOP
struct  _DMA1_ADDRESS_COUNT
struct  _DMA2_ADDRESS_COUNT
struct  _DMA1_CONTROL
struct  _DMA2_CONTROL
struct  _TIMER_CONTROL
struct  _TIMER_STATUS
struct  _NMI_STATUS
struct  _NMI_ENABLE
struct  _NMI_EXTENDED_CONTROL
struct  _EISA_CONTROL
struct  _INITIALIZATION_COMMAND_1
struct  _INITIALIZATION_COMMAND_4
struct  _DMA_EISA_MODE
struct  _DMA_EXTENDED_MODE
struct  _PARTITION_INFORMATION_NEC
struct  _DRIVE_LAYOUT_INFORMATION_NEC

Defines

#define DMA_BANK_A31_A24_DR0   0xe05
#define DMA_BANK_A31_A24_DR1   0xe07
#define DMA_BANK_A31_A24_DR2   0xe09
#define DMA_BANK_A31_A24_DR3   0xe0b
#define DMA_INC_ENABLE_A31_A24   0xe0f
#define DMA2_BANK_A31_A24_DR5   0xf07
#define DMA2_BANK_A31_A24_DR6   0xf09
#define DMA2_BANK_A31_A24_DR7   0xf0b
#define DMA2_INC_ENABLE_A31_A24   0xf0f
#define DMA2_MODE_CHANGE   0xf4
#define DMA2_MODE_8237_COMP   0x0
#define DMA2_MODE_71037_A   0x1
#define DMA2_MODE_71037_B   0x2
#define DMA2_MODE_71037_C   0x3
#define DMA_STATUS   0xc8
#define DMA_COMMAND   0xc8
#define SINGLE_MASK   0xca
#define MODE   0xcb
#define CLEAR_BYTE_POINTER   0xcc
#define CLEAR_MASK   0xce
#define TM_SIGNAL_END_OF_COUNT   0
#define TM_ONE_SHOT   1
#define TM_RATE_GENERATOR   2
#define TM_SQUARE_WAVE   3
#define TM_SOFTWARE_STROBE   4
#define TM_HARDWARE_STROBE   5
#define SB_COUNTER_LATCH   0
#define SB_LSB_BYTE   1
#define SB_MSB_BYTE   2
#define SB_LSB_THEN_MSB   3
#define SELECT_COUNTER_0   0
#define SELECT_COUNTER_1   1
#define SELECT_COUNTER_2   2
#define SELECT_READ_BACK   3
#define TIMER_CLOCK_IN   1193167
#define NONSPECIFIC_END_OF_INTERRUPT   0x20
#define SPECIFIC_END_OF_INTERRUPT   0x60
#define EISA_EXTERNAL_INTERRUPTS_1   0xf8
#define EISA_EXTERNAL_INTERRUPTS_2   0xbe
#define VERIFY_TRANSFER   0x00
#define READ_TRANSFER   0x01
#define WRITE_TRANSFER   0x02
#define DEMAND_REQUEST_MODE   0x00
#define SINGLE_REQUEST_MODE   0x01
#define BLOCK_REQUEST_MODE   0x02
#define CASCADE_REQUEST_MODE   0x03
#define BY_BYTE_8_BITS   0
#define BY_WORD_16_BITS   1
#define BY_BYTE_32_BITS   2
#define BY_BYTE_16_BITS   3
#define COMPATIBLITY_TIMING   0
#define TYPE_A_TIMING   1
#define TYPE_B_TIMING   2
#define BURST_TIMING   3
#define DMA_SETMASK   4
#define DMA_CLEARMASK   0
#define DMA_READ   4
#define DMA_WRITE   8
#define DMA_SINGLE_TRANSFER   0x40
#define DMA_AUTO_INIT   0x10
#define NOTDMA_MINIMUM_PHYSICAL_ADDRESS   0x0f00000

Typedefs

typedef _DMA_PAGE DMA_PAGE
typedef _DMA_PAGEPDMA_PAGE
typedef _DMA_CHANNEL_STOP DMA_CHANNEL_STOP
typedef _DMA_CHANNEL_STOPPDMA_CHANNEL_STOP
typedef _DMA1_ADDRESS_COUNT DMA1_ADDRESS_COUNT
typedef _DMA1_ADDRESS_COUNTPDMA1_ADDRESS_COUNT
typedef _DMA2_ADDRESS_COUNT DMA2_ADDRESS_COUNT
typedef _DMA2_ADDRESS_COUNTPDMA2_ADDRESS_COUNT
typedef _DMA1_CONTROL DMA1_CONTROL
typedef _DMA1_CONTROLPDMA1_CONTROL
typedef _DMA2_CONTROL DMA2_CONTROL
typedef _DMA2_CONTROLPDMA2_CONTROL
typedef _TIMER_CONTROL TIMER_CONTROL
typedef _TIMER_CONTROLPTIMER_CONTROL
typedef _TIMER_STATUS TIMER_STATUS
typedef _TIMER_STATUSPTIMER_STATUS
typedef _NMI_STATUS NMI_STATUS
typedef _NMI_STATUSPNMI_STATUS
typedef _NMI_ENABLE NMI_ENABLE
typedef _NMI_ENABLEPNMI_ENABLE
typedef _NMI_EXTENDED_CONTROL NMI_EXTENDED_CONTROL
typedef _NMI_EXTENDED_CONTROLPNMI_EXTENDED_CONTROL
typedef _EISA_CONTROL EISA_CONTROL
typedef _EISA_CONTROLPEISA_CONTROL
typedef _INITIALIZATION_COMMAND_1 INITIALIZATION_COMMAND_1
typedef _INITIALIZATION_COMMAND_1PINITIALIZATION_COMMAND_1
typedef _INITIALIZATION_COMMAND_4 INITIALIZATION_COMMAND_4
typedef _INITIALIZATION_COMMAND_4PINITIALIZATION_COMMAND_4
typedef _DMA_EISA_MODE DMA_EISA_MODE
typedef _DMA_EISA_MODEPDMA_EISA_MODE
typedef _DMA_EXTENDED_MODE DMA_EXTENDED_MODE
typedef _DMA_EXTENDED_MODEPDMA_EXTENDED_MODE
typedef _PARTITION_INFORMATION_NEC PARTITION_INFORMATION_NEC
typedef _PARTITION_INFORMATION_NECPPARTITION_INFORMATION_NEC
typedef _DRIVE_LAYOUT_INFORMATION_NEC DRIVE_LAYOUT_INFORMATION_NEC
typedef _DRIVE_LAYOUT_INFORMATION_NECPDRIVE_LAYOUT_INFORMATION_NEC

Functions

VOID FASTCALL xHalExamineMBR (IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONG MBRTypeIdentifier, OUT PVOID *Buffer)
VOID FASTCALL xHalIoAssignDriveLetters (IN struct _LOADER_PARAMETER_BLOCK *LoaderBlock, IN PSTRING NtDeviceName, OUT PUCHAR NtSystemPath, OUT PSTRING NtSystemPathString)
NTSTATUS FASTCALL xHalIoReadPartitionTable (IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN BOOLEAN ReturnRecognizedPartitions, OUT struct _DRIVE_LAYOUT_INFORMATION **PartitionBuffer)
NTSTATUS FASTCALL xHalIoSetPartitionInformation (IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONG PartitionNumber, IN ULONG PartitionType)
NTSTATUS FASTCALL xHalIoWritePartitionTable (IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONG SectorsPerTrack, IN ULONG NumberOfHeads, IN struct _DRIVE_LAYOUT_INFORMATION *PartitionBuffer)

Variables

UCHAR Over16MBMemoryFlag


Define Documentation

#define BLOCK_REQUEST_MODE   0x02
 

Definition at line 374 of file nec98.h.

#define BURST_TIMING   3
 

Definition at line 405 of file nec98.h.

#define BY_BYTE_16_BITS   3
 

Definition at line 396 of file nec98.h.

#define BY_BYTE_32_BITS   2
 

Definition at line 395 of file nec98.h.

#define BY_BYTE_8_BITS   0
 

Definition at line 393 of file nec98.h.

#define BY_WORD_16_BITS   1
 

Definition at line 394 of file nec98.h.

#define CASCADE_REQUEST_MODE   0x03
 

Definition at line 375 of file nec98.h.

#define CLEAR_BYTE_POINTER   0xcc
 

Definition at line 59 of file nec98.h.

#define CLEAR_MASK   0xce
 

Definition at line 60 of file nec98.h.

#define COMPATIBLITY_TIMING   0
 

Definition at line 402 of file nec98.h.

#define DEMAND_REQUEST_MODE   0x00
 

Definition at line 372 of file nec98.h.

#define DMA2_BANK_A31_A24_DR5   0xf07
 

Definition at line 41 of file nec98.h.

#define DMA2_BANK_A31_A24_DR6   0xf09
 

Definition at line 42 of file nec98.h.

#define DMA2_BANK_A31_A24_DR7   0xf0b
 

Definition at line 43 of file nec98.h.

#define DMA2_INC_ENABLE_A31_A24   0xf0f
 

Definition at line 44 of file nec98.h.

#define DMA2_MODE_71037_A   0x1
 

Definition at line 51 of file nec98.h.

#define DMA2_MODE_71037_B   0x2
 

Definition at line 52 of file nec98.h.

#define DMA2_MODE_71037_C   0x3
 

Definition at line 53 of file nec98.h.

#define DMA2_MODE_8237_COMP   0x0
 

Definition at line 50 of file nec98.h.

#define DMA2_MODE_CHANGE   0xf4
 

Definition at line 49 of file nec98.h.

#define DMA_AUTO_INIT   0x10
 

Definition at line 419 of file nec98.h.

#define DMA_BANK_A31_A24_DR0   0xe05
 

Definition at line 31 of file nec98.h.

#define DMA_BANK_A31_A24_DR1   0xe07
 

Definition at line 32 of file nec98.h.

#define DMA_BANK_A31_A24_DR2   0xe09
 

Definition at line 33 of file nec98.h.

#define DMA_BANK_A31_A24_DR3   0xe0b
 

Definition at line 34 of file nec98.h.

#define DMA_CLEARMASK   0
 

Definition at line 415 of file nec98.h.

#define DMA_COMMAND   0xc8
 

Definition at line 56 of file nec98.h.

#define DMA_INC_ENABLE_A31_A24   0xe0f
 

Definition at line 35 of file nec98.h.

#define DMA_READ   4
 

Definition at line 416 of file nec98.h.

#define DMA_SETMASK   4
 

Definition at line 414 of file nec98.h.

#define DMA_SINGLE_TRANSFER   0x40
 

Definition at line 418 of file nec98.h.

#define DMA_STATUS   0xc8
 

Definition at line 55 of file nec98.h.

#define DMA_WRITE   8
 

Definition at line 417 of file nec98.h.

#define EISA_EXTERNAL_INTERRUPTS_1   0xf8
 

Definition at line 345 of file nec98.h.

#define EISA_EXTERNAL_INTERRUPTS_2   0xbe
 

Definition at line 346 of file nec98.h.

#define MODE   0xcb
 

Definition at line 58 of file nec98.h.

#define NONSPECIFIC_END_OF_INTERRUPT   0x20
 

Definition at line 338 of file nec98.h.

#define NOTDMA_MINIMUM_PHYSICAL_ADDRESS   0x0f00000
 

Definition at line 455 of file nec98.h.

#define READ_TRANSFER   0x01
 

Definition at line 365 of file nec98.h.

#define SB_COUNTER_LATCH   0
 

Definition at line 202 of file nec98.h.

#define SB_LSB_BYTE   1
 

Definition at line 203 of file nec98.h.

#define SB_LSB_THEN_MSB   3
 

Definition at line 205 of file nec98.h.

#define SB_MSB_BYTE   2
 

Definition at line 204 of file nec98.h.

#define SELECT_COUNTER_0   0
 

Definition at line 211 of file nec98.h.

#define SELECT_COUNTER_1   1
 

Definition at line 212 of file nec98.h.

#define SELECT_COUNTER_2   2
 

Definition at line 213 of file nec98.h.

#define SELECT_READ_BACK   3
 

Definition at line 214 of file nec98.h.

#define SINGLE_MASK   0xca
 

Definition at line 57 of file nec98.h.

#define SINGLE_REQUEST_MODE   0x01
 

Definition at line 373 of file nec98.h.

#define SPECIFIC_END_OF_INTERRUPT   0x60
 

Definition at line 339 of file nec98.h.

#define TIMER_CLOCK_IN   1193167
 

Definition at line 220 of file nec98.h.

#define TM_HARDWARE_STROBE   5
 

Definition at line 196 of file nec98.h.

#define TM_ONE_SHOT   1
 

Definition at line 192 of file nec98.h.

#define TM_RATE_GENERATOR   2
 

Definition at line 193 of file nec98.h.

#define TM_SIGNAL_END_OF_COUNT   0
 

Definition at line 191 of file nec98.h.

#define TM_SOFTWARE_STROBE   4
 

Definition at line 195 of file nec98.h.

#define TM_SQUARE_WAVE   3
 

Definition at line 194 of file nec98.h.

#define TYPE_A_TIMING   1
 

Definition at line 403 of file nec98.h.

#define TYPE_B_TIMING   2
 

Definition at line 404 of file nec98.h.

#define VERIFY_TRANSFER   0x00
 

Definition at line 364 of file nec98.h.

#define WRITE_TRANSFER   0x02
 

Definition at line 366 of file nec98.h.


Typedef Documentation

typedef struct _DMA1_ADDRESS_COUNT DMA1_ADDRESS_COUNT
 

typedef struct _DMA1_CONTROL DMA1_CONTROL
 

typedef struct _DMA2_ADDRESS_COUNT DMA2_ADDRESS_COUNT
 

typedef struct _DMA2_CONTROL DMA2_CONTROL
 

typedef struct _DMA_CHANNEL_STOP DMA_CHANNEL_STOP
 

typedef struct _DMA_EISA_MODE DMA_EISA_MODE
 

typedef struct _DMA_EXTENDED_MODE DMA_EXTENDED_MODE
 

typedef struct _DMA_PAGE DMA_PAGE
 

typedef struct _DRIVE_LAYOUT_INFORMATION_NEC DRIVE_LAYOUT_INFORMATION_NEC
 

typedef struct _EISA_CONTROL EISA_CONTROL
 

typedef struct _INITIALIZATION_COMMAND_1 INITIALIZATION_COMMAND_1
 

typedef struct _INITIALIZATION_COMMAND_4 INITIALIZATION_COMMAND_4
 

typedef struct _NMI_ENABLE NMI_ENABLE
 

typedef struct _NMI_EXTENDED_CONTROL NMI_EXTENDED_CONTROL
 

typedef struct _NMI_STATUS NMI_STATUS
 

typedef struct _PARTITION_INFORMATION_NEC PARTITION_INFORMATION_NEC
 

typedef struct _DMA1_ADDRESS_COUNT * PDMA1_ADDRESS_COUNT
 

typedef struct _DMA1_CONTROL * PDMA1_CONTROL
 

typedef struct _DMA2_ADDRESS_COUNT * PDMA2_ADDRESS_COUNT
 

typedef struct _DMA2_CONTROL * PDMA2_CONTROL
 

typedef struct _DMA_CHANNEL_STOP * PDMA_CHANNEL_STOP
 

typedef struct _DMA_EISA_MODE * PDMA_EISA_MODE
 

typedef struct _DMA_EXTENDED_MODE * PDMA_EXTENDED_MODE
 

typedef struct _DMA_PAGE * PDMA_PAGE
 

typedef struct _DRIVE_LAYOUT_INFORMATION_NEC * PDRIVE_LAYOUT_INFORMATION_NEC
 

typedef struct _EISA_CONTROL * PEISA_CONTROL
 

typedef struct _INITIALIZATION_COMMAND_1 * PINITIALIZATION_COMMAND_1
 

typedef struct _INITIALIZATION_COMMAND_4 * PINITIALIZATION_COMMAND_4
 

typedef struct _NMI_ENABLE * PNMI_ENABLE
 

typedef struct _NMI_EXTENDED_CONTROL * PNMI_EXTENDED_CONTROL
 

typedef struct _NMI_STATUS * PNMI_STATUS
 

typedef struct _PARTITION_INFORMATION_NEC * PPARTITION_INFORMATION_NEC
 

typedef struct _TIMER_CONTROL * PTIMER_CONTROL
 

typedef struct _TIMER_STATUS * PTIMER_STATUS
 

typedef struct _TIMER_CONTROL TIMER_CONTROL
 

typedef struct _TIMER_STATUS TIMER_STATUS
 


Function Documentation

VOID FASTCALL xHalExamineMBR IN PDEVICE_OBJECT  DeviceObject,
IN ULONG  SectorSize,
IN ULONG  MBRTypeIdentifier,
OUT PVOID *  Buffer
 

Definition at line 190 of file drivesup.c.

References ASSERT, BOOT_RECORD_SIGNATURE, BOOT_SIGNATURE_OFFSET, Buffer, ExAllocatePoolWithTag, Executive, ExFreePool(), FALSE, _IO_STACK_LOCATION::Flags, IoBuildSynchronousFsdRequest(), IoCallDriver, IoGetNextIrpStackLocation, IRP_MJ_READ, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NonPagedPoolCacheAligned, NT_SUCCESS, NTSTATUS(), NULL, PAGE_SIZE, PARTITION_TABLE_OFFSET, _PARTITION_DESCRIPTOR::PartitionType, PUSHORT, SectorSize, SL_OVERRIDE_VERIFY_VOLUME, and VOID().

00199 : 00200 00201 Given a master boot record type (MBR - the zero'th sector on the disk), 00202 read the master boot record of a disk. If the MBR is found to be of that 00203 type, allocate a structure whose layout is dependant upon that partition 00204 type, fill with the appropriate values, and return a pointer to that buffer 00205 in the output parameter. 00206 00207 The best example for a use of this routine is to support Ontrack 00208 systems DiskManager software. Ontrack software lays down a special 00209 partition describing the entire drive. The special partition type 00210 (0x54) will be recognized and a couple of longwords of data will 00211 be passed back in a buffer for a disk driver to act upon. 00212 00213 Arguments: 00214 00215 DeviceObject - The device object describing the entire drive. 00216 00217 SectorSize - The minimum number of bytes that an IO operation can 00218 fetch. 00219 00220 MBRIndentifier - A value that will be searched for in the 00221 in the MBR. This routine will understand 00222 the semantics implied by this value. 00223 00224 Buffer - Pointer to a buffer that returns data according to the 00225 type of MBR searched for. If the MBR is not of the 00226 type asked for, the buffer will not be allocated and this 00227 pointer will be NULL. It is the responsibility of the 00228 caller of HalExamineMBR to deallocate the buffer. The 00229 caller should deallocate the memory ASAP. 00230 00231 Return Value: 00232 00233 None. 00234 00235 --*/ 00236 00237 { 00238 00239 00240 LARGE_INTEGER partitionTableOffset; 00241 PUCHAR readBuffer = (PUCHAR) NULL; 00242 KEVENT event; 00243 IO_STATUS_BLOCK ioStatus; 00244 PIRP irp; 00245 PPARTITION_DESCRIPTOR partitionTableEntry; 00246 NTSTATUS status = STATUS_SUCCESS; 00247 ULONG readSize; 00248 00249 *Buffer = NULL; 00250 // 00251 // Determine the size of a read operation to ensure that at least 512 00252 // bytes are read. This will guarantee that enough data is read to 00253 // include an entire partition table. Note that this code assumes that 00254 // the actual sector size of the disk (if less than 512 bytes) is a 00255 // multiple of 2, a fairly reasonable assumption. 00256 // 00257 00258 if (SectorSize >= 512) { 00259 readSize = SectorSize; 00260 } else { 00261 readSize = 512; 00262 } 00263 00264 // 00265 // Start at sector 0 of the device. 00266 // 00267 00268 partitionTableOffset = RtlConvertUlongToLargeInteger( 0 ); 00269 00270 // 00271 // Allocate a buffer that will hold the reads. 00272 // 00273 00274 readBuffer = ExAllocatePoolWithTag( 00275 NonPagedPoolCacheAligned, 00276 PAGE_SIZE>readSize?PAGE_SIZE:readSize, 00277 'btsF' 00278 ); 00279 00280 if (readBuffer == NULL) { 00281 return; 00282 } 00283 00284 // 00285 // Read record containing partition table. 00286 // 00287 // Create a notification event object to be used while waiting for 00288 // the read request to complete. 00289 // 00290 00291 KeInitializeEvent( &event, NotificationEvent, FALSE ); 00292 00293 irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 00294 DeviceObject, 00295 readBuffer, 00296 readSize, 00297 &partitionTableOffset, 00298 &event, 00299 &ioStatus ); 00300 00301 if (!irp) { 00302 ExFreePool(readBuffer); 00303 return; 00304 } else { 00305 PIO_STACK_LOCATION irpStack; 00306 irpStack = IoGetNextIrpStackLocation(irp); 00307 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 00308 } 00309 00310 status = IoCallDriver( DeviceObject, irp ); 00311 00312 if (status == STATUS_PENDING) { 00313 (VOID) KeWaitForSingleObject( &event, 00314 Executive, 00315 KernelMode, 00316 FALSE, 00317 (PLARGE_INTEGER) NULL); 00318 status = ioStatus.Status; 00319 } 00320 00321 if (!NT_SUCCESS( status )) { 00322 ExFreePool(readBuffer); 00323 return; 00324 } 00325 00326 // 00327 // Check for Boot Record signature. 00328 // 00329 00330 if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) { 00331 ExFreePool(readBuffer); 00332 return; 00333 } 00334 00335 // 00336 // Check for DM type partition. 00337 // 00338 00339 partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]); 00340 00341 if (partitionTableEntry->PartitionType != MBRTypeIdentifier) { 00342 00343 // 00344 // The partition type isn't what the caller cares about. 00345 // 00346 ExFreePool(readBuffer); 00347 00348 } else { 00349 00350 if (partitionTableEntry->PartitionType == 0x54) { 00351 00352 // 00353 // Rather than allocate a new piece of memory to return 00354 // the data - just use the memory allocated for the buffer. 00355 // We can assume the caller will delete this shortly. 00356 // 00357 00358 ((PULONG)readBuffer)[0] = 63; 00359 *Buffer = readBuffer; 00360 00361 } else if (partitionTableEntry->PartitionType == 0x55) { 00362 00363 // 00364 // EzDrive Parititon. Simply return the pointer to non-null 00365 // There is no skewing here. 00366 // 00367 00368 *Buffer = readBuffer; 00369 00370 } else { 00371 00372 ASSERT(partitionTableEntry->PartitionType == 0x55); 00373 00374 } 00375 00376 } 00377 00378 }

VOID FASTCALL xHalIoAssignDriveLetters IN struct _LOADER_PARAMETER_BLOCK LoaderBlock,
IN PSTRING  NtDeviceName,
OUT PUCHAR  NtSystemPath,
OUT PSTRING  NtSystemPathString
 

Definition at line 1243 of file drivesup.c.

References BOOTABLE_PARTITION, _CONFIGURATION_INFORMATION::CdRomCount, DbgPrint, _CONFIGURATION_INFORMATION::DiskCount, DiskPartitionName, ExAllocatePoolWithTag, ExFreePool(), FALSE, _CONFIGURATION_INFORMATION::FloppyCount, FT_PARTITION, HalpEnableAutomaticDriveLetterAssignment(), HalpIsOldStyleFloppy(), HalpNextDriveLetter(), HalpQueryDriveLayout(), HalpQueryPartitionType(), HalpSetMountLetter(), IoCreateSymbolicLink(), IoGetConfigurationInformation(), IoRemoteBootClient, KeBugCheck(), L, LOGICAL_PARTITION, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, PAGED_CODE, PCONFIGURATION_INFORMATION, PRIMARY_PARTITION, RtlAnsiStringToUnicodeString(), RtlFreeUnicodeString(), RtlInitAnsiString(), RtlInitString(), RtlInitUnicodeString(), RtlPrefixUnicodeString(), SETUPBLK_FLAGS_REMOTE_INSTALL, SETUPBLK_FLAGS_SYSPREP_INSTALL, sprintf(), strlen(), TRUE, and ZwOpenFile().

01252 : 01253 01254 This routine assigns DOS drive letters to eligible disk partitions 01255 and CDROM drives. It also maps the partition containing the NT 01256 boot path to \SystemRoot. In NT, objects are built for all partition 01257 types except 0 (unused) and 5 (extended). But drive letters are assigned 01258 only to recognized partition types (1, 4, 6, 7, e). 01259 01260 Drive letter assignment is done in several stages: 01261 01262 1) For each CdRom: 01263 Determine if sticky letters are assigned and reserve the letter. 01264 01265 2) For each disk: 01266 Determine how many primary partitions and which is bootable. 01267 Determine which partitions already have 'sticky letters' 01268 and create their symbolic links. 01269 Create a bit map for each disk that idicates which partitions 01270 require default drive letter assignments. 01271 01272 3) For each disk: 01273 Assign default drive letters for the bootable 01274 primary partition or the first nonbootable primary partition. 01275 01276 4) For each disk: 01277 Assign default drive letters for the partitions in 01278 extended volumes. 01279 01280 5) For each disk: 01281 Assign default drive letters for the remaining (ENHANCED) 01282 primary partitions. 01283 01284 6) Assign A: and B: to the first two floppies in the system if they 01285 exist. Then assign remaining floppies next available drive letters. 01286 01287 7) Assign drive letters to CdRoms (either sticky or default). 01288 01289 Arguments: 01290 01291 LoaderBlock - pointer to a loader parameter block. 01292 01293 NtDeviceName - pointer to the boot device name string used 01294 to resolve NtSystemPath. 01295 01296 Return Value: 01297 01298 None. 01299 01300 --*/ 01301 01302 { 01303 PUCHAR ntName; 01304 STRING ansiString; 01305 UNICODE_STRING unicodeString; 01306 PUCHAR ntPhysicalName; 01307 STRING ansiPhysicalString; 01308 UNICODE_STRING unicodePhysicalString; 01309 NTSTATUS status; 01310 OBJECT_ATTRIBUTES objectAttributes; 01311 PCONFIGURATION_INFORMATION configurationInformation; 01312 ULONG diskCount; 01313 ULONG floppyCount; 01314 HANDLE deviceHandle; 01315 IO_STATUS_BLOCK ioStatusBlock; 01316 ULONG diskNumber; 01317 ULONG i, j; 01318 UCHAR driveLetter; 01319 WCHAR deviceNameBuffer[50]; 01320 UNICODE_STRING deviceName, floppyPrefix, cdromPrefix; 01321 PDRIVE_LAYOUT_INFORMATION layout; 01322 BOOLEAN bootable; 01323 ULONG partitionType; 01324 ULONG skip; 01325 ULONG diskCountIncrement; 01326 ULONG actualDiskCount = 0; 01327 01328 PAGED_CODE(); 01329 01330 // 01331 // Get the count of devices from the registry. 01332 // 01333 01334 configurationInformation = IoGetConfigurationInformation(); 01335 01336 diskCount = configurationInformation->DiskCount; 01337 floppyCount = configurationInformation->FloppyCount; 01338 01339 // 01340 // Allocate general NT name buffer. 01341 // 01342 01343 ntName = ExAllocatePoolWithTag( NonPagedPool, 128, 'btsF'); 01344 01345 ntPhysicalName = ExAllocatePoolWithTag( NonPagedPool, 64, 'btsF'); 01346 01347 if (ntName == NULL || ntPhysicalName == NULL) { 01348 01349 KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED ); 01350 01351 } 01352 01353 // 01354 // If we're doing a remote boot, set NtSystemPath appropriately. 01355 // 01356 01357 if (IoRemoteBootClient) { 01358 01359 PUCHAR p; 01360 PUCHAR q; 01361 01362 // 01363 // If this is a remote boot setup boot, NtBootPathName is of the 01364 // form <server><share>\setup<install-directory><platform>. 01365 // We want the root of the X: drive to be the root of the install 01366 // directory. 01367 // 01368 // If this is a normal remote boot, NtBootPathName is of the form 01369 // <server><share>\images<machine>\winnt. We want the root of 01370 // the X: drive to be the root of the machine directory. 01371 // 01372 // Thus in either case, we need to remove all but the last element 01373 // of the path. 01374 // 01375 // Find the beginning of the last element of the path (including 01376 // the leading backslash). 01377 // 01378 01379 p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator 01380 q = NULL; 01381 if ( (p != NULL) && (*(p+1) == 0) ) { 01382 01383 // 01384 // NtBootPathName ends with a backslash, so we need to back up 01385 // to the previous backslash. 01386 // 01387 01388 q = p; 01389 *q = 0; 01390 p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator 01391 *q = '\\'; 01392 } 01393 if ( p == NULL ) { 01394 KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED ); 01395 } 01396 01397 // 01398 // Set NtSystemPath to X:<last element of path>. Note that the symbolic 01399 // link for X: is created in io\ioinit.c\IopInitializeBootDrivers. 01400 // 01401 // Note that we use X: for the textmode setup phase of a remote 01402 // installation. But for a true remote boot, we use C:. 01403 // 01404 01405 #if defined(REMOTE_BOOT) 01406 if ((LoaderBlock->SetupLoaderBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL | 01407 SETUPBLK_FLAGS_SYSPREP_INSTALL)) == 0) { 01408 NtSystemPath[0] = 'C'; 01409 } else 01410 #endif 01411 { 01412 NtSystemPath[0] = 'X'; 01413 } 01414 NtSystemPath[1] = ':'; 01415 strcpy(&NtSystemPath[2], p ); 01416 if ( q != NULL ) { 01417 NtSystemPath[strlen(NtSystemPath)-1] = '\0'; // remove trailing backslash 01418 } 01419 RtlInitString(NtSystemPathString, NtSystemPath); 01420 01421 } 01422 01423 // 01424 // For each disk ... 01425 // 01426 01427 diskCountIncrement = 0; 01428 for (diskNumber = 0; diskNumber < diskCount; diskNumber++) { 01429 01430 // 01431 // Create ANSI name string for physical disk. 01432 // 01433 01434 sprintf( ntName, DiskPartitionName, diskNumber, 0 ); 01435 01436 // 01437 // Convert to unicode string. 01438 // 01439 01440 RtlInitAnsiString( &ansiString, ntName ); 01441 01442 RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE ); 01443 01444 InitializeObjectAttributes( &objectAttributes, 01445 &unicodeString, 01446 OBJ_CASE_INSENSITIVE, 01447 NULL, 01448 NULL ); 01449 01450 // 01451 // Open device by name. 01452 // 01453 01454 status = ZwOpenFile( &deviceHandle, 01455 FILE_READ_DATA | SYNCHRONIZE, 01456 &objectAttributes, 01457 &ioStatusBlock, 01458 FILE_SHARE_READ, 01459 FILE_SYNCHRONOUS_IO_NONALERT ); 01460 01461 if (NT_SUCCESS( status )) { 01462 01463 // 01464 // The device was successfully opened. Generate a DOS device name 01465 // for the drive itself. 01466 // 01467 01468 sprintf( ntPhysicalName, "\\DosDevices\\PhysicalDrive%d", diskNumber ); 01469 01470 RtlInitAnsiString( &ansiPhysicalString, ntPhysicalName ); 01471 01472 RtlAnsiStringToUnicodeString( &unicodePhysicalString, &ansiPhysicalString, TRUE ); 01473 01474 IoCreateSymbolicLink( &unicodePhysicalString, &unicodeString ); 01475 01476 RtlFreeUnicodeString( &unicodePhysicalString ); 01477 01478 ZwClose(deviceHandle); 01479 01480 actualDiskCount = diskNumber + 1; 01481 } 01482 01483 RtlFreeUnicodeString( &unicodeString ); 01484 01485 if (!NT_SUCCESS( status )) { 01486 01487 #if DBG 01488 DbgPrint( "IoAssignDriveLetters: Failed to open %s\n", ntName ); 01489 #endif // DBG 01490 01491 // 01492 // This may be a sparse name space. Try going farther but 01493 // not forever. 01494 // 01495 01496 if (diskCountIncrement < 50) { 01497 diskCountIncrement++; 01498 diskCount++; 01499 } 01500 } 01501 01502 } // end for diskNumber ... 01503 01504 ExFreePool( ntName ); 01505 ExFreePool( ntPhysicalName ); 01506 01507 diskCount -= diskCountIncrement; 01508 if (actualDiskCount > diskCount) { 01509 diskCount = actualDiskCount; 01510 } 01511 01512 for (i = 0; i < diskCount; i++) { 01513 01514 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i); 01515 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01516 01517 status = HalpQueryDriveLayout(&deviceName, &layout); 01518 if (!NT_SUCCESS(status)) { 01519 layout = NULL; 01520 } 01521 01522 bootable = FALSE; 01523 for (j = 1; ; j++) { 01524 01525 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d", 01526 i, j); 01527 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01528 01529 status = HalpQueryPartitionType(&deviceName, layout, 01530 &partitionType); 01531 if (!NT_SUCCESS(status)) { 01532 break; 01533 } 01534 01535 if (partitionType != BOOTABLE_PARTITION) { 01536 continue; 01537 } 01538 01539 bootable = TRUE; 01540 01541 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE); 01542 break; 01543 } 01544 01545 if (bootable) { 01546 if (layout) { 01547 ExFreePool(layout); 01548 } 01549 continue; 01550 } 01551 01552 for (j = 1; ; j++) { 01553 01554 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d", 01555 i, j); 01556 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01557 01558 status = HalpQueryPartitionType(&deviceName, layout, 01559 &partitionType); 01560 if (!NT_SUCCESS(status)) { 01561 break; 01562 } 01563 01564 if (partitionType != PRIMARY_PARTITION) { 01565 continue; 01566 } 01567 01568 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE); 01569 break; 01570 } 01571 01572 if (layout) { 01573 ExFreePool(layout); 01574 } 01575 } 01576 01577 for (i = 0; i < diskCount; i++) { 01578 01579 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i); 01580 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01581 01582 status = HalpQueryDriveLayout(&deviceName, &layout); 01583 if (!NT_SUCCESS(status)) { 01584 layout = NULL; 01585 } 01586 01587 for (j = 1; ; j++) { 01588 01589 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d", 01590 i, j); 01591 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01592 01593 status = HalpQueryPartitionType(&deviceName, layout, 01594 &partitionType); 01595 if (!NT_SUCCESS(status)) { 01596 break; 01597 } 01598 01599 if (partitionType != LOGICAL_PARTITION) { 01600 continue; 01601 } 01602 01603 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE); 01604 } 01605 01606 if (layout) { 01607 ExFreePool(layout); 01608 } 01609 } 01610 01611 for (i = 0; i < diskCount; i++) { 01612 01613 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i); 01614 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01615 01616 status = HalpQueryDriveLayout(&deviceName, &layout); 01617 if (!NT_SUCCESS(status)) { 01618 layout = NULL; 01619 } 01620 01621 skip = 0; 01622 for (j = 1; ; j++) { 01623 01624 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d", 01625 i, j); 01626 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01627 01628 status = HalpQueryPartitionType(&deviceName, layout, 01629 &partitionType); 01630 if (!NT_SUCCESS(status)) { 01631 break; 01632 } 01633 01634 if (partitionType == BOOTABLE_PARTITION) { 01635 skip = j; 01636 } else if (partitionType == PRIMARY_PARTITION) { 01637 if (!skip) { 01638 skip = j; 01639 } 01640 } 01641 } 01642 01643 for (j = 1; ; j++) { 01644 01645 if (j == skip) { 01646 continue; 01647 } 01648 01649 swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d", 01650 i, j); 01651 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01652 01653 status = HalpQueryPartitionType(&deviceName, layout, 01654 &partitionType); 01655 if (!NT_SUCCESS(status)) { 01656 break; 01657 } 01658 01659 if (partitionType != PRIMARY_PARTITION && 01660 partitionType != FT_PARTITION) { 01661 01662 continue; 01663 } 01664 01665 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE); 01666 } 01667 01668 if (layout) { 01669 ExFreePool(layout); 01670 } 01671 } 01672 01673 for (i = 0; i < floppyCount; i++) { 01674 01675 swprintf(deviceNameBuffer, L"\\Device\\Floppy%d", i); 01676 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01677 01678 if (!HalpIsOldStyleFloppy(&deviceName)) { 01679 continue; 01680 } 01681 01682 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE); 01683 } 01684 01685 for (i = 0; i < floppyCount; i++) { 01686 01687 swprintf(deviceNameBuffer, L"\\Device\\Floppy%d", i); 01688 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01689 01690 if (HalpIsOldStyleFloppy(&deviceName)) { 01691 continue; 01692 } 01693 01694 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE); 01695 } 01696 01697 for (i = 0; i < configurationInformation->CdRomCount; i++) { 01698 01699 swprintf(deviceNameBuffer, L"\\Device\\CdRom%d", i); 01700 RtlInitUnicodeString(&deviceName, deviceNameBuffer); 01701 01702 HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE); 01703 } 01704 01705 if (!IoRemoteBootClient) { 01706 RtlAnsiStringToUnicodeString(&unicodeString, NtDeviceName, TRUE); 01707 driveLetter = HalpNextDriveLetter(&unicodeString, NULL, NULL, TRUE); 01708 if (driveLetter) { 01709 if (driveLetter != 0xFF) { 01710 NtSystemPath[0] = driveLetter; 01711 } 01712 } else { 01713 RtlInitUnicodeString(&floppyPrefix, L"\\Device\\Floppy"); 01714 RtlInitUnicodeString(&cdromPrefix, L"\\Device\\CdRom"); 01715 if (RtlPrefixUnicodeString(&floppyPrefix, &unicodeString, TRUE)) { 01716 driveLetter = 'A'; 01717 } else if (RtlPrefixUnicodeString(&cdromPrefix, &unicodeString, TRUE)) { 01718 driveLetter = 'D'; 01719 } else { 01720 driveLetter = 'C'; 01721 } 01722 for (; driveLetter <= 'Z'; driveLetter++) { 01723 status = HalpSetMountLetter(&unicodeString, driveLetter); 01724 if (NT_SUCCESS(status)) { 01725 NtSystemPath[0] = driveLetter; 01726 } 01727 } 01728 } 01729 RtlFreeUnicodeString(&unicodeString); 01730 } 01731 01732 HalpEnableAutomaticDriveLetterAssignment(); 01733 01734 } // end IoAssignDriveLetters()

NTSTATUS FASTCALL xHalIoReadPartitionTable IN PDEVICE_OBJECT  DeviceObject,
IN ULONG  SectorSize,
IN BOOLEAN  ReturnRecognizedPartitions,
OUT struct _DRIVE_LAYOUT_INFORMATION **  PartitionBuffer
 

Definition at line 1739 of file drivesup.c.

References _PARTITION_DESCRIPTOR::ActiveFlag, ASSERT, BOOT_RECORD_SIGNATURE, BOOT_SIGNATURE_OFFSET, DebugPrint, DrivesupBreakIn, ExAllocatePoolWithTag, Executive, ExFreePool(), FALSE, _IO_STACK_LOCATION::Flags, GET_PARTITION_LENGTH, GET_STARTING_SECTOR, HalExamineMBR, HalpGetFullGeometry(), HalpIsValidPartitionEntry(), IoBuildSynchronousFsdRequest(), IoCallDriver, IoGetNextIrpStackLocation, IRP_MJ_READ, _BOOT_SECTOR_INFO::JumpByte, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NonPagedPool, NonPagedPoolCacheAligned, NT_SUCCESS, NTSTATUS(), NULL, NUM_PARTITION_TABLE_ENTRIES, PAGE_SIZE, PAGED_CODE, PARTITION_ACTIVE_FLAG, PARTITION_BUFFER_SIZE, PARTITION_TABLE_OFFSET, _PARTITION_DESCRIPTOR::PartitionType, PBOOT_SECTOR_INFO, PUSHORT, SectorSize, SL_OVERRIDE_VERIFY_VOLUME, TRUE, and VOID().

01748 : 01749 01750 This routine walks the disk reading the partition tables and creates 01751 an entry in the partition list buffer for each partition. 01752 01753 The algorithm used by this routine is two-fold: 01754 01755 1) Read each partition table and for each valid, recognized 01756 partition found, to build a descriptor in a partition list. 01757 Extended partitions are located in order to find other 01758 partition tables, but no descriptors are built for these. 01759 The partition list is built in nonpaged pool that is allocated 01760 by this routine. It is the caller's responsibility to free 01761 this pool after it has gathered the appropriate information 01762 from the list. 01763 01764 2) Read each partition table and for each and every entry, build 01765 a descriptor in the partition list. Extended partitions are 01766 located to find each partition table on the disk, and entries 01767 are built for these as well. The partition list is build in 01768 nonpaged pool that is allocated by this routine. It is the 01769 caller's responsibility to free this pool after it has copied 01770 the information back to its caller. 01771 01772 The first algorithm is used when the ReturnRecognizedPartitions flag 01773 is set. This is used to determine how many partition device objects 01774 the device driver is to create, and where each lives on the drive. 01775 01776 The second algorithm is used when the ReturnRecognizedPartitions flag 01777 is clear. This is used to find all of the partition tables and their 01778 entries for a utility such as fdisk, that would like to revamp where 01779 the partitions live. 01780 01781 Arguments: 01782 01783 DeviceObject - Pointer to device object for this disk. 01784 01785 SectorSize - Sector size on the device. 01786 01787 ReturnRecognizedPartitions - A flag indicated whether only recognized 01788 partition descriptors are to be returned, or whether all partition 01789 entries are to be returned. 01790 01791 PartitionBuffer - Pointer to the pointer of the buffer in which the list 01792 of partition will be stored. 01793 01794 Return Value: 01795 01796 The functional value is STATUS_SUCCESS if at least one sector table was 01797 read. 01798 01799 Notes: 01800 01801 It is the responsibility of the caller to deallocate the partition list 01802 buffer allocated by this routine. 01803 01804 --*/ 01805 01806 { 01807 ULONG partitionBufferSize = PARTITION_BUFFER_SIZE; 01808 PDRIVE_LAYOUT_INFORMATION newPartitionBuffer = NULL; 01809 01810 LONG partitionTableCounter = -1; 01811 01812 DISK_GEOMETRY diskGeometry; 01813 ULONGLONG endSector; 01814 ULONGLONG maxSector; 01815 ULONGLONG maxOffset; 01816 01817 LARGE_INTEGER partitionTableOffset; 01818 LARGE_INTEGER volumeStartOffset; 01819 LARGE_INTEGER tempInt; 01820 BOOLEAN primaryPartitionTable; 01821 LONG partitionNumber; 01822 PUCHAR readBuffer = (PUCHAR) NULL; 01823 KEVENT event; 01824 01825 IO_STATUS_BLOCK ioStatus; 01826 PIRP irp; 01827 PPARTITION_DESCRIPTOR partitionTableEntry; 01828 CCHAR partitionEntry; 01829 NTSTATUS status = STATUS_SUCCESS; 01830 ULONG readSize; 01831 PPARTITION_INFORMATION partitionInfo; 01832 BOOLEAN foundEZHooker = FALSE; 01833 01834 BOOLEAN mbrSignatureFound = FALSE; 01835 BOOLEAN emptyPartitionTable = TRUE; 01836 01837 PAGED_CODE(); 01838 01839 // 01840 // Create the buffer that will be passed back to the driver containing 01841 // the list of partitions on the disk. 01842 // 01843 01844 *PartitionBuffer = ExAllocatePoolWithTag( NonPagedPool, 01845 partitionBufferSize, 01846 'btsF' ); 01847 01848 if (*PartitionBuffer == NULL) { 01849 return STATUS_INSUFFICIENT_RESOURCES; 01850 } 01851 01852 // 01853 // Determine the size of a read operation to ensure that at least 512 01854 // bytes are read. This will guarantee that enough data is read to 01855 // include an entire partition table. Note that this code assumes that 01856 // the actual sector size of the disk (if less than 512 bytes) is a 01857 // multiple of 2, a fairly reasonable assumption. 01858 // 01859 01860 if (SectorSize >= 512) { 01861 readSize = SectorSize; 01862 } else { 01863 readSize = 512; 01864 } 01865 01866 // 01867 // Look to see if this is an EZDrive Disk. If it is then get the 01868 // real parititon table at 1. 01869 // 01870 01871 { 01872 01873 PVOID buff; 01874 01875 HalExamineMBR( 01876 DeviceObject, 01877 readSize, 01878 (ULONG)0x55, 01879 &buff 01880 ); 01881 01882 if (buff) { 01883 01884 foundEZHooker = TRUE; 01885 ExFreePool(buff); 01886 partitionTableOffset.QuadPart = 512; 01887 01888 } else { 01889 01890 partitionTableOffset.QuadPart = 0; 01891 01892 } 01893 01894 } 01895 01896 // 01897 // Get the drive size so we can verify that the partition table is 01898 // correct. 01899 // 01900 01901 status = HalpGetFullGeometry(DeviceObject, 01902 &diskGeometry, 01903 &maxOffset); 01904 01905 if(!NT_SUCCESS(status)) { 01906 ExFreePool(*PartitionBuffer); 01907 *PartitionBuffer = NULL; 01908 return status; 01909 } 01910 01911 // 01912 // Partition offsets need to fit on the disk or we're not going to 01913 // expose them. Partition ends are generally very very sloppy so we 01914 // need to allow some slop. Adding in a cylinders worth isn't enough 01915 // so now we'll assume that all partitions end within 2x of the real end 01916 // of the disk. 01917 // 01918 01919 endSector = maxOffset; 01920 01921 maxSector = maxOffset * 2; 01922 01923 DebugPrint((2, "MaxOffset = %#I64x, maxSector = %#I64x\n", 01924 maxOffset, maxSector)); 01925 01926 // 01927 // Indicate that the primary partition table is being read and 01928 // processed. 01929 // 01930 01931 primaryPartitionTable = TRUE; 01932 01933 // 01934 // The partitions in this volume have their start sector as 0. 01935 // 01936 01937 volumeStartOffset.QuadPart = 0; 01938 01939 // 01940 // Initialize the number of partitions in the list. 01941 // 01942 01943 partitionNumber = -1; 01944 01945 // 01946 // Allocate a buffer that will hold the reads. 01947 // 01948 01949 readBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned, 01950 PAGE_SIZE, 01951 'btsF' ); 01952 01953 if (readBuffer == NULL) { 01954 ExFreePool( *PartitionBuffer ); 01955 return STATUS_INSUFFICIENT_RESOURCES; 01956 } 01957 01958 // 01959 // Read each partition table, create an object for the partition(s) 01960 // it represents, and then if there is a link entry to another 01961 // partition table, repeat. 01962 // 01963 01964 do { 01965 01966 BOOLEAN tableIsValid; 01967 ULONG containerPartitionCount; 01968 01969 tableIsValid = TRUE; 01970 01971 // 01972 // Read record containing partition table. 01973 // 01974 // Create a notification event object to be used while waiting for 01975 // the read request to complete. 01976 // 01977 01978 KeInitializeEvent( &event, NotificationEvent, FALSE ); 01979 01980 // 01981 // Zero out the buffer we're reading into. In case we get back 01982 // STATUS_NO_DATA_DETECTED we'll be prepared. 01983 // 01984 01985 RtlZeroMemory(readBuffer, readSize); 01986 01987 irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 01988 DeviceObject, 01989 readBuffer, 01990 readSize, 01991 &partitionTableOffset, 01992 &event, 01993 &ioStatus ); 01994 01995 if (!irp) { 01996 status = STATUS_INSUFFICIENT_RESOURCES; 01997 break; 01998 } else { 01999 PIO_STACK_LOCATION irpStack; 02000 irpStack = IoGetNextIrpStackLocation(irp); 02001 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 02002 } 02003 02004 status = IoCallDriver( DeviceObject, irp ); 02005 02006 if (status == STATUS_PENDING) { 02007 (VOID) KeWaitForSingleObject( &event, 02008 Executive, 02009 KernelMode, 02010 FALSE, 02011 (PLARGE_INTEGER) NULL); 02012 status = ioStatus.Status; 02013 } 02014 02015 // 02016 // Special case - if we got a blank-check reading the sector then 02017 // pretend it was just successful so we can deal with superfloppies 02018 // where noone bothered to write anything to the non-filesystem sectors 02019 // 02020 02021 if(status == STATUS_NO_DATA_DETECTED) { 02022 status = STATUS_SUCCESS; 02023 } 02024 02025 if (!NT_SUCCESS( status )) { 02026 break; 02027 } 02028 02029 // 02030 // If EZDrive is hooking the MBR then we found the first partition table 02031 // in sector 1 rather than 0. However that partition table is relative 02032 // to sector zero. So, Even though we got it from one, reset the partition 02033 // offset to 0. 02034 // 02035 02036 if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) { 02037 02038 partitionTableOffset.QuadPart = 0; 02039 02040 } 02041 02042 // 02043 // Check for Boot Record signature. 02044 // 02045 02046 if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) { 02047 02048 DebugPrint((1, "xHalIoReadPT: No 0xaa55 found in partition table %d\n", 02049 partitionTableCounter + 1)); 02050 02051 break; 02052 02053 } else { 02054 mbrSignatureFound = TRUE; 02055 } 02056 02057 // 02058 // Copy NTFT disk signature to buffer 02059 // 02060 02061 if (partitionTableOffset.QuadPart == 0) { 02062 (*PartitionBuffer)->Signature = ((PULONG) readBuffer)[PARTITION_TABLE_OFFSET/2-1]; 02063 } 02064 02065 partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]); 02066 02067 // 02068 // Keep count of partition tables in case we have an extended partition; 02069 // 02070 02071 partitionTableCounter++; 02072 02073 // 02074 // First create the objects corresponding to the entries in this 02075 // table that are not link entries or are unused. 02076 // 02077 02078 DebugPrint((2, "Partition Table %d:\n", partitionTableCounter)); 02079 02080 for (partitionEntry = 1, containerPartitionCount = 0; 02081 partitionEntry <= NUM_PARTITION_TABLE_ENTRIES; 02082 partitionEntry++, partitionTableEntry++) { 02083 02084 DebugPrint((2, "Partition Entry %d,%d: type %#x %s\n", 02085 partitionTableCounter, 02086 partitionEntry, 02087 partitionTableEntry->PartitionType, 02088 (partitionTableEntry->ActiveFlag) ? "Active" : "")); 02089 02090 DebugPrint((2, "\tOffset %#08lx for %#08lx Sectors\n", 02091 GET_STARTING_SECTOR(partitionTableEntry), 02092 GET_PARTITION_LENGTH(partitionTableEntry))); 02093 // 02094 // Do a quick pass over the entry to see if this table is valid. 02095 // It's only fatal if the master partition table is invalid. 02096 // 02097 02098 if((HalpIsValidPartitionEntry(partitionTableEntry, 02099 maxOffset, 02100 maxSector) == FALSE) && 02101 (partitionTableCounter == 0)) { 02102 02103 ASSERT(DrivesupBreakIn == FALSE); 02104 DrivesupBreakIn = FALSE; 02105 tableIsValid = FALSE; 02106 break; 02107 02108 } 02109 // 02110 // Only one container partition is allowed per table - any more 02111 // and it's invalid. 02112 // 02113 02114 if(IsContainerPartition(partitionTableEntry->PartitionType)) { 02115 02116 containerPartitionCount++; 02117 02118 if(containerPartitionCount != 1) { 02119 02120 DebugPrint((1, "Multiple container partitions found in " 02121 "partition table %d\n - table is invalid\n", 02122 partitionTableCounter)); 02123 tableIsValid = FALSE; 02124 break; 02125 } 02126 02127 } 02128 02129 if(emptyPartitionTable) { 02130 02131 if((GET_STARTING_SECTOR(partitionTableEntry) != 0) || 02132 (GET_PARTITION_LENGTH(partitionTableEntry) != 0)) { 02133 02134 // 02135 // There's a valid, non-empty partition here. The table 02136 // is not empty. 02137 // 02138 02139 emptyPartitionTable = FALSE; 02140 } 02141 } 02142 02143 // 02144 // If the partition entry is not used or not recognized, skip 02145 // it. Note that this is only done if the caller wanted only 02146 // recognized partition descriptors returned. 02147 // 02148 02149 if (ReturnRecognizedPartitions) { 02150 02151 // 02152 // Check if partition type is 0 (unused) or 5/f (extended). 02153 // The definition of recognized partitions has broadened 02154 // to include any partition type other than 0 or 5/f. 02155 // 02156 02157 if ((partitionTableEntry->PartitionType == PARTITION_ENTRY_UNUSED) || 02158 IsContainerPartition(partitionTableEntry->PartitionType)) { 02159 02160 continue; 02161 } 02162 } 02163 02164 // 02165 // Bump up to the next partition entry. 02166 // 02167 02168 partitionNumber++; 02169 02170 if (((partitionNumber * sizeof( PARTITION_INFORMATION )) + 02171 sizeof( DRIVE_LAYOUT_INFORMATION )) > 02172 (ULONG) partitionBufferSize) { 02173 02174 // 02175 // The partition list is too small to contain all of the 02176 // entries, so create a buffer that is twice as large to 02177 // store the partition list and copy the old buffer into 02178 // the new one. 02179 // 02180 02181 newPartitionBuffer = ExAllocatePoolWithTag( NonPagedPool, 02182 partitionBufferSize << 1, 02183 'btsF' ); 02184 02185 if (newPartitionBuffer == NULL) { 02186 --partitionNumber; 02187 status = STATUS_INSUFFICIENT_RESOURCES; 02188 break; 02189 } 02190 02191 RtlMoveMemory( newPartitionBuffer, 02192 *PartitionBuffer, 02193 partitionBufferSize ); 02194 02195 ExFreePool( *PartitionBuffer ); 02196 02197 // 02198 // Reassign the new buffer to the return parameter and 02199 // reset the size of the buffer. 02200 // 02201 02202 *PartitionBuffer = newPartitionBuffer; 02203 partitionBufferSize <<= 1; 02204 } 02205 02206 // 02207 // Describe this partition table entry in the partition list 02208 // entry being built for the driver. This includes writing 02209 // the partition type, starting offset of the partition, and 02210 // the length of the partition. 02211 // 02212 02213 partitionInfo = &(*PartitionBuffer)->PartitionEntry[partitionNumber]; 02214 02215 partitionInfo->PartitionType = partitionTableEntry->PartitionType; 02216 02217 partitionInfo->RewritePartition = FALSE; 02218 02219 if (partitionTableEntry->PartitionType != PARTITION_ENTRY_UNUSED) { 02220 LONGLONG startOffset; 02221 02222 partitionInfo->BootIndicator = 02223 partitionTableEntry->ActiveFlag & PARTITION_ACTIVE_FLAG ? 02224 (BOOLEAN) TRUE : (BOOLEAN) FALSE; 02225 02226 if (IsContainerPartition(partitionTableEntry->PartitionType)) { 02227 partitionInfo->RecognizedPartition = FALSE; 02228 startOffset = volumeStartOffset.QuadPart; 02229 } else { 02230 partitionInfo->RecognizedPartition = TRUE; 02231 startOffset = partitionTableOffset.QuadPart; 02232 } 02233 02234 partitionInfo->StartingOffset.QuadPart = startOffset + 02235 UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry), 02236 SectorSize); 02237 tempInt.QuadPart = (partitionInfo->StartingOffset.QuadPart - 02238 startOffset) / SectorSize; 02239 partitionInfo->HiddenSectors = tempInt.LowPart; 02240 02241 partitionInfo->PartitionLength.QuadPart = 02242 UInt32x32To64(GET_PARTITION_LENGTH(partitionTableEntry), 02243 SectorSize); 02244 02245 } else { 02246 02247 // 02248 // Partitions that are not used do not describe any part 02249 // of the disk. These types are recorded in the partition 02250 // list buffer when the caller requested all of the entries 02251 // be returned. Simply zero out the remaining fields in 02252 // the entry. 02253 // 02254 02255 partitionInfo->BootIndicator = FALSE; 02256 partitionInfo->RecognizedPartition = FALSE; 02257 partitionInfo->StartingOffset.QuadPart = 0; 02258 partitionInfo->PartitionLength.QuadPart = 0; 02259 partitionInfo->HiddenSectors = 0; 02260 } 02261 02262 } 02263 02264 DebugPrint((2, "\n")); 02265 02266 // 02267 // If an error occurred, leave the routine now. 02268 // 02269 02270 if (!NT_SUCCESS( status )) { 02271 break; 02272 } 02273 02274 if(tableIsValid == FALSE) { 02275 02276 // 02277 // Invalidate this partition table and stop looking for new ones. 02278 // we'll build the partition list based on the ones we found 02279 // previously. 02280 // 02281 02282 partitionTableCounter--; 02283 break; 02284 } 02285 02286 // 02287 // Now check to see if there are any link entries in this table, 02288 // and if so, set up the sector address of the next partition table. 02289 // There can only be one link entry in each partition table, and it 02290 // will point to the next table. 02291 // 02292 02293 partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]); 02294 02295 // 02296 // Assume that the link entry is empty. 02297 // 02298 02299 partitionTableOffset.QuadPart = 0; 02300 02301 for (partitionEntry = 1; 02302 partitionEntry <= NUM_PARTITION_TABLE_ENTRIES; 02303 partitionEntry++, partitionTableEntry++) { 02304 02305 if (IsContainerPartition(partitionTableEntry->PartitionType)) { 02306 02307 // 02308 // Obtain the address of the next partition table on the 02309 // disk. This is the number of hidden sectors added to 02310 // the beginning of the extended partition (in the case of 02311 // logical drives), since all logical drives are relative 02312 // to the extended partition. The VolumeStartSector will 02313 // be zero if this is the primary parition table. 02314 // 02315 02316 partitionTableOffset.QuadPart = volumeStartOffset.QuadPart + 02317 UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry), 02318 SectorSize); 02319 02320 // 02321 // Set the VolumeStartSector to be the begining of the 02322 // second partition (extended partition) because all of 02323 // the offsets to the partition tables of the logical drives 02324 // are relative to this extended partition. 02325 // 02326 02327 if (primaryPartitionTable) { 02328 volumeStartOffset = partitionTableOffset; 02329 } 02330 02331 // 02332 // Update the maximum sector to be the end of the container 02333 // partition. 02334 // 02335 02336 maxSector = GET_PARTITION_LENGTH(partitionTableEntry); 02337 02338 DebugPrint((2, "MaxSector now = %#08lx\n", maxSector)); 02339 02340 // 02341 // There is only ever one link entry per partition table, 02342 // exit the loop once it has been found. 02343 // 02344 02345 break; 02346 } 02347 } 02348 02349 02350 // 02351 // All the other partitions will be logical drives. 02352 // 02353 02354 primaryPartitionTable = FALSE; 02355 02356 02357 } while (partitionTableOffset.HighPart | partitionTableOffset.LowPart); 02358 02359 // 02360 // Detect super-floppy media attempt #1. 02361 // If the media is removable and has an 0xaa55 signature on it and 02362 // is empty then check to see if we can recognize the BPB. If we recognize 02363 // a jump-byte at the beginning of the media then it's a super floppy. If 02364 // we don't then it's an unpartitioned disk. 02365 // 02366 02367 DebugPrint((4, "xHalIoReadPartitionTable: RM %d PTC %d MBR %d EPT %d\n", 02368 diskGeometry.MediaType, 02369 partitionTableCounter, 02370 mbrSignatureFound, 02371 emptyPartitionTable)); 02372 02373 if((diskGeometry.MediaType == RemovableMedia) && 02374 (partitionTableCounter == 0) && 02375 (mbrSignatureFound == TRUE) && 02376 (emptyPartitionTable == TRUE)) { 02377 02378 PBOOT_SECTOR_INFO bootSector = (PBOOT_SECTOR_INFO) readBuffer; 02379 02380 if((bootSector->JumpByte[0] == 0xeb) || 02381 (bootSector->JumpByte[0] == 0xe9)) { 02382 02383 // 02384 // We've got a superfloppy of some sort. 02385 // 02386 02387 DebugPrint((1, "xHalIoReadPartitionTable: Jump byte %#x found " 02388 "along with empty partition table - disk is a " 02389 "super floppy and has no valid MBR\n", 02390 bootSector->JumpByte)); 02391 02392 partitionTableCounter = -1; 02393 } 02394 } 02395 02396 // 02397 // If the partition table count is still -1 then we didn't find any 02398 // valid partition records. In this case we'll build a partition list 02399 // that contiains one partition spanning the entire disk. 02400 // 02401 02402 if(partitionTableCounter == -1) { 02403 02404 if((mbrSignatureFound == TRUE) || 02405 (diskGeometry.MediaType == RemovableMedia)) { 02406 02407 // 02408 // Either we found a signature but the partition layout was 02409 // invalid (for all disks) or we didn't find a signature but this 02410 // is a removable disk. Either of these two cases makes a 02411 // superfloppy. 02412 // 02413 02414 DebugPrint((1, "xHalIoReadPartitionTable: Drive %#p has no valid MBR. " 02415 "Make it into a super-floppy\n", DeviceObject)); 02416 02417 DebugPrint((1, "xHalIoReadPartitionTable: Drive has %#08lx sectors " 02418 "and is %#016I64x bytes large\n", 02419 endSector, endSector * diskGeometry.BytesPerSector)); 02420 02421 if (endSector > 0) { 02422 02423 partitionInfo = &(*PartitionBuffer)->PartitionEntry[0]; 02424 02425 partitionInfo->RewritePartition = FALSE; 02426 partitionInfo->RecognizedPartition = TRUE; 02427 partitionInfo->PartitionType = PARTITION_FAT_16; 02428 partitionInfo->BootIndicator = FALSE; 02429 02430 partitionInfo->HiddenSectors = 0; 02431 02432 partitionInfo->StartingOffset.QuadPart = 0; 02433 02434 partitionInfo->PartitionLength.QuadPart = 02435 (endSector * diskGeometry.BytesPerSector); 02436 02437 (*PartitionBuffer)->Signature = 1; 02438 02439 partitionNumber = 0; 02440 } 02441 } else { 02442 02443 // 02444 // We found no partitions. Make sure the partition count is -1 02445 // so that we setup a zeroed-out partition table below. 02446 // 02447 02448 partitionNumber = -1; 02449 } 02450 } 02451 02452 // 02453 // Fill in the first field in the PartitionBuffer. This field indicates how 02454 // many partition entries there are in the PartitionBuffer. 02455 // 02456 02457 (*PartitionBuffer)->PartitionCount = ++partitionNumber; 02458 02459 if (!partitionNumber) { 02460 02461 // 02462 // Zero out disk signature. 02463 // 02464 02465 (*PartitionBuffer)->Signature = 0; 02466 } 02467 02468 // 02469 // Deallocate read buffer if it was allocated it. 02470 // 02471 02472 if (readBuffer != NULL) { 02473 ExFreePool( readBuffer ); 02474 } 02475 02476 if (!NT_SUCCESS(status)) { 02477 ExFreePool(*PartitionBuffer); 02478 *PartitionBuffer = NULL; 02479 } 02480 return status; 02481 }

NTSTATUS FASTCALL xHalIoSetPartitionInformation IN PDEVICE_OBJECT  DeviceObject,
IN ULONG  SectorSize,
IN ULONG  PartitionNumber,
IN ULONG  PartitionType
 

Definition at line 2485 of file drivesup.c.

References BOOT_RECORD_SIGNATURE, BOOT_SIGNATURE_OFFSET, ExAllocatePoolWithTag, Executive, ExFreePool(), FALSE, _IO_STACK_LOCATION::Flags, GET_STARTING_SECTOR, HalExamineMBR, IoBuildSynchronousFsdRequest(), IoCallDriver, IoGetNextIrpStackLocation, IRP_MJ_READ, IRP_MJ_WRITE, KeInitializeEvent, KeResetEvent(), KernelMode, KeWaitForSingleObject(), NonPagedPoolCacheAligned, NT_SUCCESS, NTSTATUS(), NULL, NUM_PARTITION_TABLE_ENTRIES, PAGE_SIZE, PAGED_CODE, PARTITION_TABLE_OFFSET, _PARTITION_DESCRIPTOR::PartitionType, PUSHORT, SectorSize, SL_OVERRIDE_VERIFY_VOLUME, TRUE, and VOID().

02494 : 02495 02496 This routine is invoked when a disk device driver is asked to set the 02497 partition type in a partition table entry via an I/O control code. This 02498 control code is generally issued by the format utility just after it 02499 has formatted the partition. The format utility performs the I/O control 02500 function on the partition and the driver passes the address of the base 02501 physical device object and the number of the partition associated with 02502 the device object that the format utility has open. If this routine 02503 returns success, then the disk driver should updates its notion of the 02504 partition type for this partition in its device extension. 02505 02506 Arguments: 02507 02508 DeviceObject - Pointer to the base physical device object for the device 02509 on which the partition type is to be set. 02510 02511 SectorSize - Supplies the size of a sector on the disk in bytes. 02512 02513 PartitionNumber - Specifies the partition number on the device whose 02514 partition type is to be changed. 02515 02516 PartitionType - Specifies the new type for the partition. 02517 02518 Return Value: 02519 02520 The function value is the final status of the operation. 02521 02522 Notes: 02523 02524 This routine is synchronous. Therefore, it MUST be invoked by the disk 02525 driver's dispatch routine, or by a disk driver's thread. Likewise, all 02526 users, FSP threads, etc., must be prepared to enter a wait state when 02527 issuing the I/O control code to set the partition type for the device. 02528 02529 Note also that this routine assumes that the partition number passed 02530 in by the disk driver actually exists since the driver itself supplies 02531 this parameter. 02532 02533 Finally, note that this routine may NOT be invoked at APC_LEVEL. It 02534 must be invoked at PASSIVE_LEVEL. This is due to the fact that this 02535 routine uses a kernel event object to synchronize I/O completion on the 02536 device. The event cannot be set to the signaled state without queueing 02537 the I/O system's special kernel APC routine for I/O completion and 02538 executing it. (This rules is a bit esoteric since it only holds true 02539 if the device driver returns something other than STATUS_PENDING, which 02540 it will probably never do.) 02541 02542 --*/ 02543 02544 { 02545 02546 #define GET_STARTING_SECTOR( p ) ( \ 02547 (ULONG) (p->StartingSectorLsb0) + \ 02548 (ULONG) (p->StartingSectorLsb1 << 8) + \ 02549 (ULONG) (p->StartingSectorMsb0 << 16) + \ 02550 (ULONG) (p->StartingSectorMsb1 << 24) ) 02551 02552 PIRP irp; 02553 KEVENT event; 02554 IO_STATUS_BLOCK ioStatus; 02555 NTSTATUS status; 02556 LARGE_INTEGER partitionTableOffset; 02557 LARGE_INTEGER volumeStartOffset; 02558 PUCHAR buffer = (PUCHAR) NULL; 02559 ULONG transferSize; 02560 ULONG partitionNumber; 02561 ULONG partitionEntry; 02562 PPARTITION_DESCRIPTOR partitionTableEntry; 02563 BOOLEAN primaryPartitionTable; 02564 BOOLEAN foundEZHooker = FALSE; 02565 02566 PAGED_CODE(); 02567 02568 // 02569 // Begin by determining the size of the buffer required to read and write 02570 // the partition information to/from the disk. This is done to ensure 02571 // that at least 512 bytes are read, thereby guaranteeing that enough data 02572 // is read to include an entire partition table. Note that this code 02573 // assumes that the actual sector size of the disk (if less than 512 02574 // bytes) is a multiple of 2, a 02575 // fairly reasonable assumption. 02576 // 02577 02578 if (SectorSize >= 512) { 02579 transferSize = SectorSize; 02580 } else { 02581 transferSize = 512; 02582 } 02583 02584 02585 // 02586 // Look to see if this is an EZDrive Disk. If it is then get the 02587 // real parititon table at 1. 02588 // 02589 02590 { 02591 02592 PVOID buff; 02593 02594 HalExamineMBR( 02595 DeviceObject, 02596 transferSize, 02597 (ULONG)0x55, 02598 &buff 02599 ); 02600 02601 if (buff) { 02602 02603 foundEZHooker = TRUE; 02604 ExFreePool(buff); 02605 partitionTableOffset.QuadPart = 512; 02606 02607 } else { 02608 02609 partitionTableOffset.QuadPart = 0; 02610 02611 } 02612 02613 } 02614 02615 02616 // 02617 // The partitions in this primary partition have their start sector 0. 02618 // 02619 02620 volumeStartOffset.QuadPart = 0; 02621 02622 // 02623 // Indicate that the table being read and processed is the primary partition 02624 // table. 02625 // 02626 02627 primaryPartitionTable = TRUE; 02628 02629 // 02630 // Initialize the number of partitions found thus far. 02631 // 02632 02633 partitionNumber = 0; 02634 02635 // 02636 // Allocate a buffer that will hold the read/write data. 02637 // 02638 02639 buffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned, PAGE_SIZE, 'btsF'); 02640 if (buffer == NULL) { 02641 return STATUS_INSUFFICIENT_RESOURCES; 02642 } 02643 02644 // 02645 // Initialize a kernel event to use in synchronizing device requests 02646 // with I/O completion. 02647 // 02648 02649 KeInitializeEvent( &event, NotificationEvent, FALSE ); 02650 02651 // 02652 // Read each partition table scanning for the partition table entry that 02653 // the caller wishes to modify. 02654 // 02655 02656 do { 02657 02658 // 02659 // Read the record containing the partition table. 02660 // 02661 02662 (VOID) KeResetEvent( &event ); 02663 02664 irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 02665 DeviceObject, 02666 buffer, 02667 transferSize, 02668 &partitionTableOffset, 02669 &event, 02670 &ioStatus ); 02671 02672 if (!irp) { 02673 status = STATUS_INSUFFICIENT_RESOURCES; 02674 break; 02675 } else { 02676 PIO_STACK_LOCATION irpStack; 02677 irpStack = IoGetNextIrpStackLocation(irp); 02678 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 02679 } 02680 02681 status = IoCallDriver( DeviceObject, irp ); 02682 02683 if (status == STATUS_PENDING) { 02684 (VOID) KeWaitForSingleObject( &event, 02685 Executive, 02686 KernelMode, 02687 FALSE, 02688 (PLARGE_INTEGER) NULL ); 02689 status = ioStatus.Status; 02690 } 02691 02692 if (!NT_SUCCESS( status )) { 02693 break; 02694 } 02695 02696 // 02697 // If EZDrive is hooking the MBR then we found the first partition table 02698 // in sector 1 rather than 0. However that partition table is relative 02699 // to sector zero. So, Even though we got it from one, reset the partition 02700 // offset to 0. 02701 // 02702 02703 if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) { 02704 02705 partitionTableOffset.QuadPart = 0; 02706 02707 } 02708 02709 // 02710 // Check for a valid Boot Record signature in the partition table 02711 // record. 02712 // 02713 02714 if (((PUSHORT) buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) { 02715 status = STATUS_BAD_MASTER_BOOT_RECORD; 02716 break; 02717 } 02718 02719 partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) buffer)[PARTITION_TABLE_OFFSET]); 02720 02721 // 02722 // Scan the partition entries in this partition table to determine if 02723 // any of the entries are the desired entry. Each entry in each 02724 // table must be scanned in the same order as in IoReadPartitionTable 02725 // so that the partition table entry cooresponding to the driver's 02726 // notion of the partition number can be located. 02727 // 02728 02729 for (partitionEntry = 1; 02730 partitionEntry <= NUM_PARTITION_TABLE_ENTRIES; 02731 partitionEntry++, partitionTableEntry++) { 02732 02733 02734 // 02735 // If the partition entry is empty or for an extended, skip it. 02736 // 02737 02738 if ((partitionTableEntry->PartitionType == PARTITION_ENTRY_UNUSED) || 02739 IsContainerPartition(partitionTableEntry->PartitionType)) { 02740 continue; 02741 } 02742 02743 // 02744 // A valid partition entry that is recognized has been located. 02745 // Bump the count and check to see if this entry is the desired 02746 // entry. 02747 // 02748 02749 partitionNumber++; 02750 02751 if (partitionNumber == PartitionNumber) { 02752 02753 // 02754 // This is the desired partition that is to be changed. Simply 02755 // overwrite the partition type and write the entire partition 02756 // buffer back out to the disk. 02757 // 02758 02759 partitionTableEntry->PartitionType = (UCHAR) PartitionType; 02760 02761 (VOID) KeResetEvent( &event ); 02762 02763 irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, 02764 DeviceObject, 02765 buffer, 02766 transferSize, 02767 &partitionTableOffset, 02768 &event, 02769 &ioStatus ); 02770 02771 if (!irp) { 02772 status = STATUS_INSUFFICIENT_RESOURCES; 02773 break; 02774 } else { 02775 PIO_STACK_LOCATION irpStack; 02776 irpStack = IoGetNextIrpStackLocation(irp); 02777 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 02778 } 02779 02780 status = IoCallDriver( DeviceObject, irp ); 02781 02782 if (status == STATUS_PENDING) { 02783 (VOID) KeWaitForSingleObject( &event, 02784 Executive, 02785 KernelMode, 02786 FALSE, 02787 (PLARGE_INTEGER) NULL ); 02788 status = ioStatus.Status; 02789 } 02790 02791 break; 02792 } 02793 } 02794 02795 // 02796 // If all of the entries in the current buffer were scanned and the 02797 // desired entry was not found, then continue. Otherwise, leave the 02798 // routine. 02799 // 02800 02801 if (partitionEntry <= NUM_PARTITION_TABLE_ENTRIES) { 02802 break; 02803 } 02804 02805 // 02806 // Now scan the current buffer to locate an extended partition entry 02807 // in the table so that its partition information can be read. There 02808 // can only be one extended partition entry in each partition table, 02809 // and it will point to the next table. 02810 // 02811 02812 partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) buffer)[PARTITION_TABLE_OFFSET]); 02813 02814 for (partitionEntry = 1; 02815 partitionEntry <= NUM_PARTITION_TABLE_ENTRIES; 02816 partitionEntry++, partitionTableEntry++) { 02817 02818 if (IsContainerPartition(partitionTableEntry->PartitionType)) { 02819 02820 // 02821 // Obtain the address of the next partition table on the disk. 02822 // This is the number of hidden sectors added to the beginning 02823 // of the extended partition (in the case of logical drives), 02824 // since all logical drives are relative to the extended 02825 // partition. The starting offset of the volume will be zero 02826 // if this is the primary partition table. 02827 // 02828 02829 partitionTableOffset.QuadPart = volumeStartOffset.QuadPart + 02830 UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry), 02831 SectorSize); 02832 02833 // 02834 // Set the starting offset of the volume to be the beginning of 02835 // the second partition (the extended partition) because all of 02836 // the offsets to the partition tables of the logical drives 02837 // are relative to this extended partition. 02838 // 02839 02840 if (primaryPartitionTable) { 02841 volumeStartOffset = partitionTableOffset; 02842 } 02843 02844 break; 02845 } 02846 } 02847 02848 // 02849 // Ensure that a partition entry was located that was an extended 02850 // partition, otherwise the desired partition will never be found. 02851 // 02852 02853 if (partitionEntry > NUM_PARTITION_TABLE_ENTRIES) { 02854 status = STATUS_BAD_MASTER_BOOT_RECORD; 02855 break; 02856 } 02857 02858 // 02859 // All the other partitions will be logical drives. 02860 // 02861 02862 primaryPartitionTable = FALSE; 02863 02864 } while (partitionNumber < PartitionNumber); 02865 02866 // 02867 // If a data buffer was successfully allocated, deallocate it now. 02868 // 02869 02870 if (buffer != NULL) { 02871 ExFreePool( buffer ); 02872 } 02873 02874 return status; 02875 }

NTSTATUS FASTCALL xHalIoWritePartitionTable IN PDEVICE_OBJECT  DeviceObject,
IN ULONG  SectorSize,
IN ULONG  SectorsPerTrack,
IN ULONG  NumberOfHeads,
IN struct _DRIVE_LAYOUT_INFORMATION *  PartitionBuffer
 

Definition at line 2879 of file drivesup.c.

References BOOT_RECORD_SIGNATURE, BOOT_SIGNATURE_OFFSET, ExAllocatePoolWithTag, Executive, ExFreePool(), FALSE, _IO_STACK_LOCATION::Flags, HalExamineMBR, HalpCalculateChsValues(), IoBuildSynchronousFsdRequest(), IoCallDriver, IoGetNextIrpStackLocation, IRP_MJ_READ, IRP_MJ_WRITE, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NonPagedPoolCacheAligned, NT_SUCCESS, NTSTATUS(), NULL, NUM_PARTITION_TABLE_ENTRIES, PAGE_SIZE, PAGED_CODE, PARTITION_ACTIVE_FLAG, PARTITION_TABLE_OFFSET, PUSHORT, SectorSize, SL_OVERRIDE_VERIFY_VOLUME, TRUE, USHORT, VOID(), WHICH_BIT, and xHalGetPartialGeometry().

02889 : 02890 02891 This routine walks the disk writing the partition tables from 02892 the entries in the partition list buffer for each partition. 02893 02894 Applications that create and delete partitions should issue a 02895 IoReadPartitionTable call with the 'return recognized partitions' 02896 boolean set to false to get a full description of the system. 02897 02898 Then the drive layout structure can be modified by the application to 02899 reflect the new configuration of the disk and then is written back 02900 to the disk using this routine. 02901 02902 Arguments: 02903 02904 DeviceObject - Pointer to device object for this disk. 02905 02906 SectorSize - Sector size on the device. 02907 02908 SectorsPerTrack - Track size on the device. 02909 02910 NumberOfHeads - Same as tracks per cylinder. 02911 02912 PartitionBuffer - Pointer drive layout buffer. 02913 02914 Return Value: 02915 02916 The functional value is STATUS_SUCCESS if all writes are completed 02917 without error. 02918 02919 --*/ 02920 02921 { 02922 typedef struct _PARTITION_TABLE { 02923 PARTITION_INFORMATION PartitionEntry[4]; 02924 } PARTITION_TABLE, *PPARTITION_TABLE; 02925 02926 typedef struct _DISK_LAYOUT { 02927 ULONG TableCount; 02928 ULONG Signature; 02929 PARTITION_TABLE PartitionTable[1]; 02930 } DISK_LAYOUT, *PDISK_LAYOUT; 02931 02932 typedef struct _PTE { 02933 UCHAR ActiveFlag; // Bootable or not 02934 UCHAR StartingTrack; // Not used 02935 USHORT StartingCylinder; // Not used 02936 UCHAR PartitionType; // 12 bit FAT, 16 bit FAT etc. 02937 UCHAR EndingTrack; // Not used 02938 USHORT EndingCylinder; // Not used 02939 ULONG StartingSector; // Hidden sectors 02940 ULONG PartitionLength; // Sectors in this partition 02941 } PTE; 02942 typedef PTE UNALIGNED *PPTE; 02943 02944 // 02945 // This macro has the effect of Bit = log2(Data) 02946 // 02947 02948 #define WHICH_BIT(Data, Bit) { \ 02949 for (Bit = 0; Bit < 32; Bit++) { \ 02950 if ((Data >> Bit) == 1) { \ 02951 break; \ 02952 } \ 02953 } \ 02954 } 02955 02956 ULONG writeSize; 02957 PUSHORT writeBuffer = NULL; 02958 PPTE partitionEntry; 02959 PPARTITION_TABLE partitionTable; 02960 CCHAR shiftCount; 02961 LARGE_INTEGER partitionTableOffset; 02962 LARGE_INTEGER nextRecordOffset; 02963 ULONG partitionTableCount; 02964 ULONG partitionEntryCount; 02965 KEVENT event; 02966 IO_STATUS_BLOCK ioStatus; 02967 PIRP irp; 02968 BOOLEAN rewritePartition = FALSE; 02969 NTSTATUS status = STATUS_SUCCESS; 02970 LARGE_INTEGER tempInt; 02971 BOOLEAN foundEZHooker = FALSE; 02972 ULONG conventionalCylinders; 02973 LONGLONG diskSize; 02974 02975 BOOLEAN isSuperFloppy = FALSE; 02976 02977 // 02978 // Cast to a structure that is easier to use. 02979 // 02980 02981 PDISK_LAYOUT diskLayout = (PDISK_LAYOUT) PartitionBuffer; 02982 02983 // 02984 // Ensure that no one is calling this function illegally. 02985 // 02986 02987 PAGED_CODE(); 02988 02989 // 02990 // Determine the size of a write operation to ensure that at least 512 02991 // bytes are written. This will guarantee that enough data is written to 02992 // include an entire partition table. Note that this code assumes that 02993 // the actual sector size of the disk (if less than 512 bytes) is a 02994 // multiple of 2, a fairly reasonable assumption. 02995 // 02996 02997 if (SectorSize >= 512) { 02998 writeSize = SectorSize; 02999 } else { 03000 writeSize = 512; 03001 } 03002 03003 xHalGetPartialGeometry( DeviceObject, 03004 &conventionalCylinders, 03005 &diskSize ); 03006 03007 // 03008 // Look to see if this is an EZDrive Disk. If it is then get the 03009 // real partititon table at 1. 03010 // 03011 03012 { 03013 03014 PVOID buff; 03015 03016 HalExamineMBR( 03017 DeviceObject, 03018 writeSize, 03019 (ULONG)0x55, 03020 &buff 03021 ); 03022 03023 if (buff) { 03024 03025 foundEZHooker = TRUE; 03026 ExFreePool(buff); 03027 partitionTableOffset.QuadPart = 512; 03028 03029 } else { 03030 03031 partitionTableOffset.QuadPart = 0; 03032 03033 } 03034 03035 } 03036 03037 // 03038 // Initialize starting variables. 03039 // 03040 03041 nextRecordOffset.QuadPart = 0; 03042 03043 // 03044 // Calculate shift count for converting between byte and sector. 03045 // 03046 03047 WHICH_BIT( SectorSize, shiftCount ); 03048 03049 // 03050 // Check to see if this device is partitioned (or is being partitioned) 03051 // as a floppy. Floppys have a single partititon with hidden sector count 03052 // and partition offset equal to zero. If the disk is being partitioned 03053 // like this then we need to be sure not to write an MBR signature or 03054 // an NTFT signature to the media. 03055 // 03056 // NOTE: this is only to catch ourself when someone tries to write the 03057 // existing partition table back to disk. Any changes to the table will 03058 // result in a real MBR being written out. 03059 // 03060 03061 if(PartitionBuffer->PartitionCount == 1) { 03062 03063 PPARTITION_INFORMATION partitionEntry = PartitionBuffer->PartitionEntry; 03064 03065 if((partitionEntry->StartingOffset.QuadPart == 0) && 03066 (partitionEntry->HiddenSectors == 0)) { 03067 03068 isSuperFloppy = TRUE; 03069 03070 // 03071 // This would indeed appear to be an attempt to format a floppy. 03072 // Make sure the other parameters match the defaut values we 03073 // provide in ReadParititonTable. If they don't then fail 03074 // the write operation. 03075 // 03076 03077 if((partitionEntry->PartitionNumber != 0) || 03078 (partitionEntry->PartitionType != PARTITION_FAT_16) || 03079 (partitionEntry->BootIndicator == TRUE)) { 03080 03081 return STATUS_INVALID_PARAMETER; 03082 } 03083 03084 if(partitionEntry->RewritePartition == TRUE) { 03085 rewritePartition = TRUE; 03086 } 03087 03088 foundEZHooker = FALSE; 03089 } 03090 } 03091 03092 // 03093 // Convert partition count to partition table or boot sector count. 03094 // 03095 03096 diskLayout->TableCount = 03097 (PartitionBuffer->PartitionCount + 03098 NUM_PARTITION_TABLE_ENTRIES - 1) / 03099 NUM_PARTITION_TABLE_ENTRIES; 03100 03101 // 03102 // Allocate a buffer for the sector writes. 03103 // 03104 03105 writeBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned, PAGE_SIZE, 'btsF'); 03106 03107 if (writeBuffer == NULL) { 03108 return STATUS_INSUFFICIENT_RESOURCES; 03109 } 03110 03111 // 03112 // Point to the partition table entries in write buffer. 03113 // 03114 03115 partitionEntry = (PPTE) &writeBuffer[PARTITION_TABLE_OFFSET]; 03116 03117 for (partitionTableCount = 0; 03118 partitionTableCount < diskLayout->TableCount; 03119 partitionTableCount++) { 03120 03121 UCHAR partitionType; 03122 03123 // 03124 // the first partition table is in the mbr (physical sector 0). 03125 // other partition tables are in ebr's within the extended partition. 03126 // 03127 03128 BOOLEAN mbr = (BOOLEAN) (!partitionTableCount); 03129 LARGE_INTEGER extendedPartitionOffset; 03130 03131 // 03132 // Read the boot record that's already there into the write buffer 03133 // and save its boot code area if the signature is valid. This way 03134 // we don't clobber any boot code that might be there already. 03135 // 03136 03137 KeInitializeEvent( &event, NotificationEvent, FALSE ); 03138 03139 irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, 03140 DeviceObject, 03141 writeBuffer, 03142 writeSize, 03143 &partitionTableOffset, 03144 &event, 03145 &ioStatus ); 03146 03147 if (!irp) { 03148 status = STATUS_INSUFFICIENT_RESOURCES; 03149 break; 03150 } else { 03151 PIO_STACK_LOCATION irpStack; 03152 irpStack = IoGetNextIrpStackLocation(irp); 03153 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 03154 } 03155 03156 status = IoCallDriver( DeviceObject, irp ); 03157 03158 if (status == STATUS_PENDING) { 03159 (VOID) KeWaitForSingleObject( &event, 03160 Executive, 03161 KernelMode, 03162 FALSE, 03163 (PLARGE_INTEGER) NULL); 03164 status = ioStatus.Status; 03165 } 03166 03167 if (!NT_SUCCESS( status )) { 03168 break; 03169 } 03170 03171 // 03172 // If EZDrive is hooking the MBR then we found the first partition table 03173 // in sector 1 rather than 0. However that partition table is relative 03174 // to sector zero. So, Even though we got it from one, reset the partition 03175 // offset to 0. 03176 // 03177 03178 if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) { 03179 03180 partitionTableOffset.QuadPart = 0; 03181 03182 } 03183 03184 if(isSuperFloppy == FALSE) { 03185 03186 // 03187 // Write signature to last word of boot sector. 03188 // 03189 03190 writeBuffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE; 03191 03192 // 03193 // Write NTFT disk signature if it changed and this is the MBR. 03194 // 03195 03196 rewritePartition = FALSE; 03197 if (partitionTableOffset.QuadPart == 0) { 03198 03199 if (((PULONG)writeBuffer)[PARTITION_TABLE_OFFSET/2-1] != 03200 PartitionBuffer->Signature) { 03201 03202 ((PULONG) writeBuffer)[PARTITION_TABLE_OFFSET/2-1] = 03203 PartitionBuffer->Signature; 03204 rewritePartition = TRUE; 03205 } 03206 } 03207 03208 // 03209 // Get pointer to first partition table. 03210 // 03211 03212 partitionTable = &diskLayout->PartitionTable[partitionTableCount]; 03213 03214 // 03215 // Walk table to determine whether this boot record has changed 03216 // and update partition table in write buffer in case it needs 03217 // to be written out to disk. 03218 // 03219 03220 for (partitionEntryCount = 0; 03221 partitionEntryCount < NUM_PARTITION_TABLE_ENTRIES; 03222 partitionEntryCount++) { 03223 03224 partitionType = 03225 partitionTable->PartitionEntry[partitionEntryCount].PartitionType; 03226 03227 // 03228 // If the rewrite ISN'T true then copy then just leave the data 03229 // alone that is in the on-disk table. 03230 // 03231 03232 if (partitionTable->PartitionEntry[partitionEntryCount].RewritePartition) { 03233 03234 // 03235 // This boot record needs to be written back to disk. 03236 // 03237 03238 rewritePartition = TRUE; 03239 03240 // 03241 // Copy partition type from user buffer to write buffer. 03242 // 03243 03244 partitionEntry[partitionEntryCount].PartitionType = 03245 partitionTable->PartitionEntry[partitionEntryCount].PartitionType; 03246 03247 // 03248 // Copy the partition active flag. 03249 // 03250 03251 partitionEntry[partitionEntryCount].ActiveFlag = 03252 partitionTable->PartitionEntry[partitionEntryCount].BootIndicator ? 03253 (UCHAR) PARTITION_ACTIVE_FLAG : (UCHAR) 0; 03254 03255 if (partitionType != PARTITION_ENTRY_UNUSED) { 03256 03257 LARGE_INTEGER sectorOffset; 03258 03259 // 03260 // Calculate partition offset. 03261 // If in the mbr or the entry is not a link entry, partition offset 03262 // is sectors past last boot record. Otherwise (not in the mbr and 03263 // entry is a link entry), partition offset is sectors past start 03264 // of extended partition. 03265 // 03266 03267 if (mbr || !IsContainerPartition(partitionType)) { 03268 tempInt.QuadPart = partitionTableOffset.QuadPart; 03269 } else { 03270 tempInt.QuadPart = extendedPartitionOffset.QuadPart; 03271 } 03272 03273 sectorOffset.QuadPart = 03274 partitionTable->PartitionEntry[partitionEntryCount].StartingOffset.QuadPart - 03275 tempInt.QuadPart; 03276 03277 tempInt.QuadPart = sectorOffset.QuadPart >> shiftCount; 03278 partitionEntry[partitionEntryCount].StartingSector = tempInt.LowPart; 03279 03280 // 03281 // Calculate partition length. 03282 // 03283 03284 tempInt.QuadPart = partitionTable->PartitionEntry[partitionEntryCount].PartitionLength.QuadPart >> shiftCount; 03285 partitionEntry[partitionEntryCount].PartitionLength = tempInt.LowPart; 03286 03287 // 03288 // Fill in CHS values 03289 // 03290 03291 HalpCalculateChsValues( 03292 &partitionTable->PartitionEntry[partitionEntryCount].StartingOffset, 03293 &partitionTable->PartitionEntry[partitionEntryCount].PartitionLength, 03294 shiftCount, 03295 SectorsPerTrack, 03296 NumberOfHeads, 03297 conventionalCylinders, 03298 (PPARTITION_DESCRIPTOR) &partitionEntry[partitionEntryCount]); 03299 03300 } else { 03301 03302 // 03303 // Zero out partition entry fields in case an entry 03304 // was deleted. 03305 // 03306 03307 partitionEntry[partitionEntryCount].StartingSector = 0; 03308 partitionEntry[partitionEntryCount].PartitionLength = 0; 03309 partitionEntry[partitionEntryCount].StartingTrack = 0; 03310 partitionEntry[partitionEntryCount].EndingTrack = 0; 03311 partitionEntry[partitionEntryCount].StartingCylinder = 0; 03312 partitionEntry[partitionEntryCount].EndingCylinder = 0; 03313 } 03314 03315 } 03316 03317 if (IsContainerPartition(partitionType)) { 03318 03319 // 03320 // Save next record offset. 03321 // 03322 03323 nextRecordOffset = 03324 partitionTable->PartitionEntry[partitionEntryCount].StartingOffset; 03325 } 03326 03327 } // end for partitionEntryCount ... 03328 03329 } else { 03330 03331 // 03332 // If there's an 0xaa55 in the MBR signature, clear it out. 03333 // 03334 03335 // 03336 // BUGBUG - don't do this. 03337 // 03338 03339 if(writeBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE) { 03340 // writeBuffer[BOOT_SIGNATURE_OFFSET] += 0x1111; 03341 } 03342 } 03343 03344 if (rewritePartition == TRUE) { 03345 03346 rewritePartition = FALSE; 03347 03348 // 03349 // Create a notification event object to be used while waiting for 03350 // the write request to complete. 03351 // 03352 03353 KeInitializeEvent( &event, NotificationEvent, FALSE ); 03354 03355 if (foundEZHooker && (partitionTableOffset.QuadPart == 0)) { 03356 03357 partitionTableOffset.QuadPart = 512; 03358 03359 } 03360 irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, 03361 DeviceObject, 03362 writeBuffer, 03363 writeSize, 03364 &partitionTableOffset, 03365 &event, 03366 &ioStatus ); 03367 03368 if (!irp) { 03369 status = STATUS_INSUFFICIENT_RESOURCES; 03370 break; 03371 } else { 03372 PIO_STACK_LOCATION irpStack; 03373 irpStack = IoGetNextIrpStackLocation(irp); 03374 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 03375 } 03376 03377 status = IoCallDriver( DeviceObject, irp ); 03378 03379 if (status == STATUS_PENDING) { 03380 (VOID) KeWaitForSingleObject( &event, 03381 Executive, 03382 KernelMode, 03383 FALSE, 03384 (PLARGE_INTEGER) NULL); 03385 status = ioStatus.Status; 03386 } 03387 03388 if (!NT_SUCCESS( status )) { 03389 break; 03390 } 03391 03392 03393 if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) { 03394 03395 partitionTableOffset.QuadPart = 0; 03396 03397 } 03398 03399 } // end if (reWrite ... 03400 03401 // 03402 // Update partitionTableOffset to next boot record offset 03403 // 03404 03405 partitionTableOffset = nextRecordOffset; 03406 if(mbr) { 03407 extendedPartitionOffset = nextRecordOffset; 03408 } 03409 03410 } // end for partitionTableCount ... 03411 03412 // 03413 // Deallocate write buffer if it was allocated it. 03414 // 03415 03416 if (writeBuffer != NULL) { 03417 ExFreePool( writeBuffer ); 03418 } 03419 03420 return status; 03421 }


Variable Documentation

UCHAR Over16MBMemoryFlag
 

Definition at line 450 of file nec98.h.


Generated on Sat May 15 19:44:50 2004 for test by doxygen 1.3.7