DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/libs/porttalk/porttalk.cpp
00001 #include "config.h"
00002 #include "logging.h"
00003 
00004 #if defined(_MSC_VER)
00005 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00006 # pragma warning(disable:4267) /* ... possible loss of data */
00007 # pragma warning(disable:4305) /* truncation from double to float */
00008 #endif
00009 
00010 #if defined (_MSC_VER)
00011 # if defined (_M_IX86)/*x86 only*/
00012 void outportb(Bit32u portid, Bit8u value) {
00013   __asm mov edx,portid
00014   __asm mov al,value
00015   __asm out dx,al
00016 }
00017 
00018 Bit8u inportb(Bit32u portid) {
00019   Bit8u value;
00020   
00021   __asm mov edx,portid
00022   __asm in al,dx
00023   __asm mov value,al
00024   return value;
00025 }
00026 
00027 void outportw(Bit32u portid, Bit16u value) {
00028   __asm mov edx,portid
00029   __asm mov ax,value
00030   __asm out dx,ax
00031 }
00032 
00033 Bit16u inportw(Bit32u portid) {
00034   Bit16u value;
00035   
00036   __asm mov edx,portid
00037   __asm in ax,dx
00038   __asm mov value,ax
00039   return value;
00040 }
00041 
00042 void outportd(Bit32u portid, Bit32u value) {
00043   __asm mov edx,portid
00044   __asm mov eax,value
00045   __asm out dx,eax
00046 }
00047 
00048 Bit32u inportd(Bit32u portid) {
00049   Bit32u value;
00050   
00051   __asm mov edx,portid
00052   __asm in eax,dx
00053   __asm mov value,eax
00054   return value;
00055 }
00056 # endif
00057 #else
00058 # if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
00059 void outportb(Bit32u portid, Bit8u value) {
00060    __asm__ volatile (
00061       "movl   %0,%%edx   \n"
00062       "movb   %1,%%al      \n"
00063       "outb   %%al,%%dx   "
00064       :
00065       :   "r" (portid), "r" (value)
00066       :   "edx", "al"
00067    );
00068 }
00069 Bit8u inportb(Bit32u portid) {
00070    Bit8u value;
00071    __asm__ volatile (
00072       "movl   %1,%%edx   \n"
00073       "inb   %%dx,%%al   \n"
00074       "movb   %%al,%0      "
00075       :   "=m" (value)
00076       :   "r" (portid)
00077       :   "edx", "al", "memory"
00078    );
00079   return value;
00080 }
00081 # endif
00082 #endif
00083 
00084 #if defined(WIN32) && defined(_M_IX86)/*WIN32 x86 only*/
00085 
00086 // WIN specific
00087 #include "sdl.h"
00088 #include <windows.h>
00089 #include <winioctl.h> // NEEDED by GCC
00090 #include "porttalk.h"
00091 #include <stdio.h>
00092 #include <process.h>
00093 
00094 // PortTalk_IOCTL.h can be downloaded with PortTalk
00095 #include "PortTalk_IOCTL.h"
00096 
00097 typedef struct driverpermstruct {
00098     Bit16u offset;
00099     Bit8u value;
00100 } permblock;
00101 
00102 static HANDLE porttalkhandle=INVALID_HANDLE_VALUE;
00103 static Bit8u ioperm[8192];
00104 static bool isNT = false;
00105 
00106 bool initPorttalk() {
00107     // handles neded for starting service
00108     SC_HANDLE  ServiceManager = NULL;
00109     SC_HANDLE  PorttalkService = NULL;
00110 
00111     // check which platform we are on
00112     OSVERSIONINFO osvi;
00113     memset(&osvi,0,sizeof(OSVERSIONINFO));
00114     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00115     if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) {
00116         LOG_MSG("GET VERSION failed!");
00117         return false;
00118     }
00119     if(osvi.dwPlatformId==2) isNT=true;
00120     
00121     if(isNT && porttalkhandle==INVALID_HANDLE_VALUE) {
00122         porttalkhandle = CreateFile("\\\\.\\PortTalk", GENERIC_READ,
00123                 0, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_DEVICE, NULL);
00124 
00125         if (porttalkhandle == INVALID_HANDLE_VALUE) {
00126             Bitu retval=0;
00127             // Porttalk service is not started. Attempt to start it.
00128             ServiceManager = OpenSCManager (NULL,   // NULL is local machine
00129                     NULL,                           // default database
00130                     SC_MANAGER_ENUMERATE_SERVICE);  // desired access
00131             
00132             if(ServiceManager==NULL) {
00133                 // No rights to enumerate services
00134                 LOG_MSG("You do not have the rights to enumerate services.");
00135                 return false;
00136             }
00137             PorttalkService = OpenService(ServiceManager,
00138                                   "PortTalk",       // service name
00139                                   SERVICE_START);   // desired access
00140             
00141             if(PorttalkService==NULL) {
00142                 // get causes
00143                 switch (retval=GetLastError()) {
00144                 case ERROR_ACCESS_DENIED:
00145                     LOG_MSG("You do not have the rights to enumerate services.");
00146                     break;
00147                 case ERROR_SERVICE_DOES_NOT_EXIST:
00148                     LOG_MSG("Porttalk service is not installed.");
00149                     break;
00150                 default:
00151                     LOG_MSG("Error %d occured accessing porttalk dirver.",retval);
00152                     break;
00153                 }
00154                 goto error;
00155             }
00156 
00157             // start it
00158             retval = StartService (PorttalkService,
00159                 0,             // number of arguments
00160                 NULL);         // pointer to arguments
00161             if(!retval) {
00162                 // couldn't start it
00163                 if((retval=GetLastError())!=ERROR_SERVICE_ALREADY_RUNNING) {
00164                     LOG_MSG("Could not start Porttalk service. Error %d.",retval);
00165                     goto error;
00166                 }
00167             }
00168             CloseServiceHandle(PorttalkService);
00169             CloseServiceHandle(ServiceManager);
00170 
00171             // try again
00172             porttalkhandle = CreateFile("\\\\.\\PortTalk", GENERIC_READ,
00173                 0, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_DEVICE, NULL);
00174             
00175             if (porttalkhandle == INVALID_HANDLE_VALUE) {
00176                 // bullshit
00177                 LOG_MSG(
00178                     "Porttalk driver could not be opened after being started successully.");
00179                 return false;
00180             }
00181 
00182         }
00183         for(size_t i = 0; i < sizeof(ioperm); i++) ioperm[i]=0xff;
00184         int retval;
00185 
00186         DeviceIoControl(    porttalkhandle,
00187                 IOCTL_IOPM_RESTRICT_ALL_ACCESS,
00188                 NULL,0,
00189                 NULL,0,
00190                 (LPDWORD)&retval,
00191                 NULL);
00192     }
00193     return true;
00194 error:
00195     if(PorttalkService) CloseServiceHandle(PorttalkService);
00196     if(ServiceManager) CloseServiceHandle(ServiceManager);
00197     return false;
00198 }
00199 void addIOPermission(Bit16u port) {
00200     if(isNT)
00201         ioperm[(port>>3)]&=(~(1<<(port&0x7)));
00202 }
00203 
00204 bool setPermissionList() {
00205     if(!isNT) return true;
00206     if(porttalkhandle!=INVALID_HANDLE_VALUE) {
00207         permblock b;
00208         int pid = _getpid();
00209         int reetval=0;
00210         Bit32u retval=0;
00211         //output permission list to driver
00212         for(size_t i = 0; i < sizeof(ioperm);i++) {
00213             b.offset=i;
00214             b.value=ioperm[i];
00215             
00216             retval=DeviceIoControl( porttalkhandle,
00217                             IOCTL_SET_IOPM,
00218                             (LPDWORD)&b,3,
00219                             NULL,0,
00220                             (LPDWORD)&reetval,
00221                             NULL);
00222             if(retval==0) return false;
00223         }
00224         
00225         
00226         reetval=DeviceIoControl(    porttalkhandle,
00227                             IOCTL_ENABLE_IOPM_ON_PROCESSID,
00228                             (LPDWORD)&pid,4,
00229                             NULL,0,
00230                             (LPDWORD)&retval,
00231                             NULL);
00232         SDL_Delay(100);
00233         return reetval!=0;
00234     }
00235     else return false;
00236 }
00237 #endif
00238 
00239 #ifdef LINUX
00240 # if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
00241 // This Linux ioperm only works up to port 0x3FF
00242 #include <sys/perm.h>
00243 
00244 bool initPorttalk() {
00245     if(ioperm(0x3da,1,1) < 0) return false;
00246     return true;
00247 }
00248 
00249 void addIOPermission(Bit16u port) {
00250     ioperm(port,1,1);
00251 }
00252 
00253 bool setPermissionList() {
00254     return true;
00255 }
00256 
00257 # endif
00258 #endif
00259