/**************************************************************************** * * SciTech OS Portability Manager Library * * ======================================================================== * * The contents of this file are subject to the SciTech MGL Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.scitechsoft.com/mgl-license.txt * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. * * The Initial Developer of the Original Code is SciTech Software, Inc. * All Rights Reserved. * * ======================================================================== * * Language: ANSI C * Environment: 32-bit Windows NT device drivers. * * Description: Implementation for the OS Portability Manager Library, which * contains functions to implement OS specific services in a * generic, cross platform API. Porting the OS Portability * Manager library is the first step to porting any SciTech * products to a new platform. * ****************************************************************************/ #include "pmapi.h" #include "drvlib/os/os.h" #include "sdd/sddhelp.h" #include "mtrr.h" #include "oshdr.h" /*--------------------------- Global variables ----------------------------*/ char _PM_cntPath[PM_MAX_PATH] = ""; char _PM_nucleusPath[PM_MAX_PATH] = ""; static void (PMAPIP fatalErrorCleanup)(void) = NULL; static char *szNTWindowsKey = "\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion"; static char *szNTSystemRoot = "SystemRoot"; static char *szMachineNameKey = "\\REGISTRY\\Machine\\System\\CurrentControlSet\\control\\ComputerName\\ComputerName"; static char *szMachineNameKeyNT = "\\REGISTRY\\Machine\\System\\CurrentControlSet\\control\\ComputerName\\ActiveComputerName"; static char *szMachineName = "ComputerName"; /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** REMARKS: Initialise the PM library. ****************************************************************************/ void PMAPI PM_init(void) { /* Initialiase the MTRR module */ MTRR_init(); } /**************************************************************************** REMARKS: Return the operating system type identifier. ****************************************************************************/ long PMAPI PM_getOSType(void) { return _OS_WINNTDRV; } /**************************************************************************** REMARKS: Return the runtime type identifier. ****************************************************************************/ int PMAPI PM_getModeType(void) { return PM_386; } /**************************************************************************** REMARKS: Add a file directory separator to the end of the filename. ****************************************************************************/ void PMAPI PM_backslash(char *s) { uint pos = strlen(s); if (s[pos-1] != '\\') { s[pos] = '\\'; s[pos+1] = '\0'; } } /**************************************************************************** REMARKS: Add a user defined PM_fatalError cleanup function. ****************************************************************************/ void PMAPI PM_setFatalErrorCleanup( void (PMAPIP cleanup)(void)) { fatalErrorCleanup = cleanup; } /**************************************************************************** REMARKS: Handle fatal errors internally in the driver. ****************************************************************************/ void PMAPI PM_fatalError( const char *msg) { ULONG BugCheckCode = 0; ULONG MoreBugCheckData[4] = {0}; char *p; ULONG len; if (fatalErrorCleanup) fatalErrorCleanup(); #ifdef DBG /* Send output to debugger, just return so as not to force a reboot */ #pragma message("INFO: building for debug, PM_fatalError() re-routed") DBGMSG2("SDDHELP> PM_fatalError(): ERROR: %s\n", msg); return ; #endif /* KeBugCheckEx brings down the system in a controlled */ /* manner when the caller discovers an unrecoverable */ /* inconsistency that would corrupt the system if */ /* the caller continued to run. */ /* */ /* hack - dump the first 20 chars in hex using the variables */ /* provided - Each ULONG is equal to four characters... */ for(len = 0; len < 20; len++) if (msg[len] == (char)0) break; /* This looks bad but it's quick and reliable... */ p = (char *)&BugCheckCode; if(len > 0) p[3] = msg[0]; if(len > 1) p[2] = msg[1]; if(len > 2) p[1] = msg[2]; if(len > 3) p[0] = msg[3]; p = (char *)&MoreBugCheckData[0]; if(len > 4) p[3] = msg[4]; if(len > 5) p[2] = msg[5]; if(len > 6) p[1] = msg[6]; if(len > 7) p[0] = msg[7]; p = (char *)&MoreBugCheckData[1]; if(len > 8) p[3] = msg[8]; if(len > 9) p[2] = msg[9]; if(len > 10) p[1] = msg[10]; if(len > 11) p[0] = msg[11]; p = (char *)&MoreBugCheckData[2]; if(len > 12) p[3] = msg[12]; if(len > 13) p[2] = msg[13]; if(len > 14) p[1] = msg[14]; if(len > 15) p[0] = msg[15]; p = (char *)&MoreBugCheckData[3]; if(len > 16) p[3] = msg[16]; if(len > 17) p[2] = msg[17]; if(len > 18) p[1] = msg[18]; if(len > 19) p[0] = msg[19]; /* Halt the system! */ KeBugCheckEx(BugCheckCode, MoreBugCheckData[0], MoreBugCheckData[1], MoreBugCheckData[2], MoreBugCheckData[3]); } /**************************************************************************** REMARKS: Return the current operating system path or working directory. ****************************************************************************/ char * PMAPI PM_getCurrentPath( char *path, int maxLen) { strncpy(path,_PM_cntPath,maxLen); path[maxLen-1] = 0; return path; } /**************************************************************************** PARAMETERS: szKey - Key to query (can contain version number formatting) szValue - Value to get information for value - Place to store the registry key data read size - Size of the string buffer to read into RETURNS: true if the key was found, false if not. ****************************************************************************/ static ibool REG_queryString( char *szKey, const char *szValue, char *value, DWORD size) { ibool status; NTSTATUS rval; ULONG length; HANDLE Handle; OBJECT_ATTRIBUTES keyAttributes; UNICODE_STRING *uniKey = NULL; UNICODE_STRING *uniValue = NULL; PKEY_VALUE_FULL_INFORMATION fullInfo = NULL; STRING stringdata; UNICODE_STRING unidata; /* Convert strings to UniCode */ status = false; if ((uniKey = _PM_CStringToUnicodeString(szKey)) == NULL) goto Exit; if ((uniValue = _PM_CStringToUnicodeString(szValue)) == NULL) goto Exit; /* Open the key */ InitializeObjectAttributes( &keyAttributes, uniKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); rval = ZwOpenKey( &Handle, KEY_ALL_ACCESS, &keyAttributes ); if (!NT_SUCCESS(rval)) goto Exit; /* Query the value */ length = sizeof (KEY_VALUE_FULL_INFORMATION) + size * sizeof(WCHAR); if ((fullInfo = ExAllocatePool (PagedPool, length)) == NULL) goto Exit; RtlZeroMemory(fullInfo, length); rval = ZwQueryValueKey (Handle, uniValue, KeyValueFullInformation, fullInfo, length, &length); if (NT_SUCCESS (rval)) { /* Create the UniCode string so we can convert it */ unidata.Buffer = (PWCHAR)(((PCHAR)fullInfo) + fullInfo->DataOffset); unidata.Length = (USHORT)fullInfo->DataLength; unidata.MaximumLength = (USHORT)fullInfo->DataLength + sizeof(WCHAR); /* Convert unicode univalue to ansi string. */ rval = RtlUnicodeStringToAnsiString(&stringdata, &unidata, TRUE); if (NT_SUCCESS(rval)) { strcpy(value,stringdata.Buffer); status = true; } } Exit: if (fullInfo) ExFreePool(fullInfo); if (uniKey) _PM_FreeUnicodeString(uniKey); if (uniValue) _PM_FreeUnicodeString(uniValue); return status; } /**************************************************************************** REMARKS: Return the drive letter for the boot drive. ****************************************************************************/ char PMAPI PM_getBootDrive(void) { char path[256]; if (REG_queryString(szNTWindowsKey,szNTSystemRoot,path,sizeof(path))) return 'c'; return path[0]; } /**************************************************************************** REMARKS: Return the path to the VBE/AF driver files. ****************************************************************************/ const char * PMAPI PM_getVBEAFPath(void) { return "c:\\"; } /**************************************************************************** REMARKS: Return the path to the Nucleus driver files. ****************************************************************************/ const char * PMAPI PM_getNucleusPath(void) { static char path[256]; if (strlen(_PM_nucleusPath) > 0) { strcpy(path,_PM_nucleusPath); PM_backslash(path); return path; } if (!REG_queryString(szNTWindowsKey,szNTSystemRoot,path,sizeof(path))) strcpy(path,"c:\\winnt"); PM_backslash(path); strcat(path,"system32\\nucleus"); return path; } /**************************************************************************** REMARKS: Return the path to the Nucleus configuration files. ****************************************************************************/ const char * PMAPI PM_getNucleusConfigPath(void) { static char path[256]; strcpy(path,PM_getNucleusPath()); PM_backslash(path); strcat(path,"config"); return path; } /**************************************************************************** REMARKS: Return a unique identifier for the machine if possible. ****************************************************************************/ const char * PMAPI PM_getUniqueID(void) { return PM_getMachineName(); } /**************************************************************************** REMARKS: Get the name of the machine on the network. ****************************************************************************/ const char * PMAPI PM_getMachineName(void) { static char name[256]; if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name))) return name; if (REG_queryString(szMachineNameKeyNT,szMachineName,name,sizeof(name))) return name; return "Unknown"; } /**************************************************************************** REMARKS: Check if a key has been pressed. ****************************************************************************/ int PMAPI PM_kbhit(void) { /* Not used in NT drivers */ return true; } /**************************************************************************** REMARKS: Wait for and return the next keypress. ****************************************************************************/ int PMAPI PM_getch(void) { /* Not used in NT drivers */ return 0xD; } /**************************************************************************** REMARKS: Open a console for output to the screen, creating the main event handling window if necessary. ****************************************************************************/ PM_HWND PMAPI PM_openConsole( PM_HWND hwndUser, int device, int xRes, int yRes, int bpp, ibool fullScreen) { /* Not used in NT drivers */ (void)hwndUser; (void)device; (void)xRes; (void)yRes; (void)bpp; (void)fullScreen; return NULL; } /**************************************************************************** REMARKS: Find the size of the console state buffer. ****************************************************************************/ int PMAPI PM_getConsoleStateSize(void) { /* Not used in NT drivers */ return 1; } /**************************************************************************** REMARKS: Save the state of the console. ****************************************************************************/ void PMAPI PM_saveConsoleState( void *stateBuf, PM_HWND hwndConsole) { /* Not used in NT drivers */ (void)stateBuf; (void)hwndConsole; } /**************************************************************************** REMARKS: Set the suspend application callback for the fullscreen console. ****************************************************************************/ void PMAPI PM_setSuspendAppCallback( PM_saveState_cb saveState) { /* Not used in NT drivers */ (void)saveState; } /**************************************************************************** REMARKS: Restore the console state. ****************************************************************************/ void PMAPI PM_restoreConsoleState( const void *stateBuf, PM_HWND hwndConsole) { /* Not used in NT drivers */ (void)stateBuf; (void)hwndConsole; } /**************************************************************************** REMARKS: Close the fullscreen console. ****************************************************************************/ void PMAPI PM_closeConsole( PM_HWND hwndConsole) { /* Not used in NT drivers */ (void)hwndConsole; } /**************************************************************************** REMARKS: Set the location of the OS console cursor. ****************************************************************************/ void PMAPI PM_setOSCursorLocation( int x, int y) { /* Nothing to do for Windows */ (void)x; (void)y; } /**************************************************************************** REMARKS: Set the width of the OS console. ****************************************************************************/ void PMAPI PM_setOSScreenWidth( int width, int height) { /* Nothing to do for Windows */ (void)width; (void)height; } /**************************************************************************** REMARKS: Maps a shared memory block into process address space. Does nothing since the memory blocks are already globally mapped into all processes. ****************************************************************************/ void * PMAPI PM_mapToProcess( void *base, ulong limit) { /* Not used anymore */ (void)base; (void)limit; return NULL; } /**************************************************************************** REMARKS: Execute the POST on the secondary BIOS for a controller. ****************************************************************************/ ibool PMAPI PM_doBIOSPOST( ushort axVal, ulong BIOSPhysAddr, void *mappedBIOS, ulong BIOSLen) { /* This may not be possible in NT and should be done by the OS anyway */ (void)axVal; (void)BIOSPhysAddr; (void)mappedBIOS; (void)BIOSLen; return false; } /**************************************************************************** REMARKS: Return a pointer to the real mode BIOS data area. ****************************************************************************/ void * PMAPI PM_getBIOSPointer(void) { /* Note that on NT this probably does not do what we expect! */ return PM_mapPhysicalAddr(0x400, 0x1000, true); } /**************************************************************************** REMARKS: Return a pointer to 0xA0000 physical VGA graphics framebuffer. ****************************************************************************/ void * PMAPI PM_getA0000Pointer(void) { return PM_mapPhysicalAddr(0xA0000,0xFFFF,false); } /**************************************************************************** REMARKS: Sleep for the specified number of milliseconds. ****************************************************************************/ void PMAPI PM_sleep( ulong milliseconds) { /* We never use this in NT drivers */ (void)milliseconds; } /**************************************************************************** REMARKS: Return the base I/O port for the specified COM port. ****************************************************************************/ int PMAPI PM_getCOMPort(int port) { /* TODO: Re-code this to determine real values using the Plug and Play */ /* manager for the OS. */ switch (port) { case 0: return 0x3F8; case 1: return 0x2F8; case 2: return 0x3E8; case 3: return 0x2E8; } return 0; } /**************************************************************************** REMARKS: Return the base I/O port for the specified LPT port. ****************************************************************************/ int PMAPI PM_getLPTPort(int port) { /* TODO: Re-code this to determine real values using the Plug and Play */ /* manager for the OS. */ switch (port) { case 0: return 0x3BC; case 1: return 0x378; case 2: return 0x278; } return 0; } /**************************************************************************** REMARKS: Returns available memory. Not possible under Windows. ****************************************************************************/ void PMAPI PM_availableMemory( ulong *physical, ulong *total) { *physical = *total = 0; } /**************************************************************************** REMARKS: OS specific shared libraries not supported inside a VxD ****************************************************************************/ PM_MODULE PMAPI PM_loadLibrary( const char *szDLLName) { /* Not used in NT drivers */ (void)szDLLName; return NULL; } /**************************************************************************** REMARKS: OS specific shared libraries not supported inside a VxD ****************************************************************************/ void * PMAPI PM_getProcAddress( PM_MODULE hModule, const char *szProcName) { /* Not used in NT drivers */ (void)hModule; (void)szProcName; return NULL; } /**************************************************************************** REMARKS: OS specific shared libraries not supported inside a VxD ****************************************************************************/ void PMAPI PM_freeLibrary( PM_MODULE hModule) { /* Not used in NT drivers */ (void)hModule; } /**************************************************************************** REMARKS: Function to find the first file matching a search criteria in a directory. ****************************************************************************/ void *PMAPI PM_findFirstFile( const char *filename, PM_findData *findData) { /* TODO: This function should start a directory enumeration search */ /* given the filename (with wildcards). The data should be */ /* converted and returned in the findData standard form. */ (void)filename; (void)findData; return PM_FILE_INVALID; } /**************************************************************************** REMARKS: Function to find the next file matching a search criteria in a directory. ****************************************************************************/ ibool PMAPI PM_findNextFile( void *handle, PM_findData *findData) { /* TODO: This function should find the next file in directory enumeration */ /* search given the search criteria defined in the call to */ /* PM_findFirstFile. The data should be converted and returned */ /* in the findData standard form. */ (void)handle; (void)findData; return false; } /**************************************************************************** REMARKS: Function to close the find process ****************************************************************************/ void PMAPI PM_findClose( void *handle) { /* TODO: This function should close the find process. This may do */ /* nothing for some OS'es. */ (void)handle; } /**************************************************************************** REMARKS: Function to determine if a drive is a valid drive or not. Under Unix this function will return false for anything except a value of 3 (considered the root drive, and equivalent to C: for non-Unix systems). The drive numbering is: 1 - Drive A: 2 - Drive B: 3 - Drive C: etc ****************************************************************************/ ibool PMAPI PM_driveValid( char drive) { /* Not supported in NT drivers */ (void)drive; return false; } /**************************************************************************** REMARKS: Function to get the current working directory for the specififed drive. Under Unix this will always return the current working directory regardless of what the value of 'drive' is. ****************************************************************************/ void PMAPI PM_getdcwd( int drive, char *dir, int len) { /* Not supported in NT drivers */ (void)drive; (void)dir; (void)len; } /**************************************************************************** PARAMETERS: base - The starting physical base address of the region size - The size in bytes of the region type - Type to place into the MTRR register RETURNS: Error code describing the result. REMARKS: Function to enable write combining for the specified region of memory. ****************************************************************************/ int PMAPI PM_enableWriteCombine( ulong base, ulong size, uint type) { return MTRR_enableWriteCombine(base,size,type); } /**************************************************************************** REMARKS: Function to change the file attributes for a specific file. ****************************************************************************/ void PMAPI PM_setFileAttr( const char *filename, uint attrib) { NTSTATUS status; ACCESS_MASK DesiredAccess = GENERIC_READ | GENERIC_WRITE; OBJECT_ATTRIBUTES ObjectAttributes; ULONG ShareAccess = FILE_SHARE_READ; ULONG CreateDisposition = FILE_OPEN; HANDLE FileHandle = NULL; UNICODE_STRING *uniFile = NULL; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasic; char kernelFilename[PM_MAX_PATH+5]; ULONG FileAttributes = 0; /* Convert file attribute flags */ if (attrib & PM_FILE_READONLY) FileAttributes |= FILE_ATTRIBUTE_READONLY; if (attrib & PM_FILE_ARCHIVE) FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; if (attrib & PM_FILE_HIDDEN) FileAttributes |= FILE_ATTRIBUTE_HIDDEN; if (attrib & PM_FILE_SYSTEM) FileAttributes |= FILE_ATTRIBUTE_SYSTEM; /* Add prefix for addressing the file system. "\??\" is short for "\DosDevices\" */ strcpy(kernelFilename, "\\??\\"); strcat(kernelFilename, filename); /* Convert filename string to ansi string */ if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL) goto Exit; /* Must open a file to query it's attributes */ InitializeObjectAttributes (&ObjectAttributes, uniFile, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwCreateFile( &FileHandle, DesiredAccess | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, /*AllocationSize OPTIONAL, */ FILE_ATTRIBUTE_NORMAL, ShareAccess, CreateDisposition, FILE_RANDOM_ACCESS, /*CreateOptions, */ NULL, /*EaBuffer OPTIONAL, */ 0 /*EaLength (required if EaBuffer) */ ); if (!NT_SUCCESS (status)) goto Exit; /* Query timestamps */ status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); if (!NT_SUCCESS (status)) goto Exit; /* Change the four bits we change */ FileBasic.FileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); FileBasic.FileAttributes |= FileAttributes; /* Set timestamps */ ZwSetInformationFile( FileHandle, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); Exit: if (FileHandle) ZwClose(FileHandle); if (uniFile) _PM_FreeUnicodeString(uniFile); return; } /**************************************************************************** REMARKS: Function to get the file attributes for a specific file. ****************************************************************************/ uint PMAPI PM_getFileAttr( const char *filename) { NTSTATUS status; ACCESS_MASK DesiredAccess = GENERIC_READ | GENERIC_WRITE; OBJECT_ATTRIBUTES ObjectAttributes; ULONG ShareAccess = FILE_SHARE_READ; ULONG CreateDisposition = FILE_OPEN; HANDLE FileHandle = NULL; UNICODE_STRING *uniFile = NULL; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasic; char kernelFilename[PM_MAX_PATH+5]; ULONG FileAttributes = 0; uint retval = 0; /* Add prefix for addressing the file system. "\??\" is short for "\DosDevices\" */ strcpy(kernelFilename, "\\??\\"); strcat(kernelFilename, filename); /* Convert filename string to ansi string */ if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL) goto Exit; /* Must open a file to query it's attributes */ InitializeObjectAttributes (&ObjectAttributes, uniFile, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwCreateFile( &FileHandle, DesiredAccess | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, /*AllocationSize OPTIONAL, */ FILE_ATTRIBUTE_NORMAL, ShareAccess, CreateDisposition, FILE_RANDOM_ACCESS, /*CreateOptions, */ NULL, /*EaBuffer OPTIONAL, */ 0 /*EaLength (required if EaBuffer) */ ); if (!NT_SUCCESS (status)) goto Exit; /* Query timestamps */ status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); if (!NT_SUCCESS (status)) goto Exit; /* Translate the file attributes */ if (FileBasic.FileAttributes & FILE_ATTRIBUTE_READONLY) retval |= PM_FILE_READONLY; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) retval |= PM_FILE_ARCHIVE; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_HIDDEN) retval |= PM_FILE_HIDDEN; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_SYSTEM) retval |= PM_FILE_SYSTEM; Exit: if (FileHandle) ZwClose(FileHandle); if (uniFile) _PM_FreeUnicodeString(uniFile); return retval; } /**************************************************************************** REMARKS: Function to create a directory. ****************************************************************************/ ibool PMAPI PM_mkdir( const char *filename) { /* Not supported in NT drivers */ (void)filename; return false; } /**************************************************************************** REMARKS: Function to remove a directory. ****************************************************************************/ ibool PMAPI PM_rmdir( const char *filename) { /* Not supported in NT drivers */ (void)filename; return false; } /**************************************************************************** REMARKS: Function to get the file time and date for a specific file. ****************************************************************************/ ibool PMAPI PM_getFileTime( const char *filename, ibool gmTime, PM_time *time) { /* Not supported in NT drivers */ (void)filename; (void)gmTime; (void)time; return false; } /**************************************************************************** REMARKS: Function to set the file time and date for a specific file. ****************************************************************************/ ibool PMAPI PM_setFileTime( const char *filename, ibool gmTime, PM_time *time) { /* Not supported in NT drivers */ (void)filename; (void)gmTime; (void)time; return false; }