]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/vxd/pm.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / vxd / pm.c
1 /****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  32-bit Windows VxD
26 *
27 * Description:  Implementation for the OS Portability Manager Library, which
28 *               contains functions to implement OS specific services in a
29 *               generic, cross platform API. Porting the OS Portability
30 *               Manager library is the first step to porting any SciTech
31 *               products to a new platform.
32 *
33 ****************************************************************************/
34
35 #include "pmapi.h"
36 #include "drvlib/os/os.h"
37 #include "sdd/sddhelp.h"
38 #include "mtrr.h"
39
40 /*--------------------------- Global variables ----------------------------*/
41
42 #define MAX_MEMORY_SHARED           100
43 #define MAX_MEMORY_MAPPINGS         100
44
45 typedef struct {
46     void    *linear;
47     ulong   global;
48     ulong   length;
49     int     npages;
50     } memshared;
51
52 typedef struct {
53     ulong   physical;
54     ulong   linear;
55     ulong   length;
56     int     npages;
57     ibool   isCached;
58     } mmapping;
59
60 static int          numMappings = 0;
61 static memshared    shared[MAX_MEMORY_MAPPINGS] = {0};
62 static mmapping     maps[MAX_MEMORY_MAPPINGS];
63 extern ibool        _PM_haveBIOS;
64 char                _PM_cntPath[PM_MAX_PATH] = "";
65 char                _PM_nucleusPath[PM_MAX_PATH] = "";
66 uchar               *_PM_rmBufAddr = NULL;
67 ushort _VARAPI      _PM_savedDS = 0;
68 static uchar        _PM_oldCMOSRegA;
69 static uchar        _PM_oldCMOSRegB;
70 PM_intHandler       _PM_rtcHandler = NULL;
71 IRQHANDLE           RTCIRQHandle = 0;
72 VPICD_HWInt_THUNK   RTCInt_Thunk;
73
74 static char *szWindowsKey       = "Software\\Microsoft\\Windows\\CurrentVersion";
75 static char *szSystemRoot       = "SystemRoot";
76 static char *szMachineNameKey   = "System\\CurrentControlSet\\control\\ComputerName\\ComputerName";
77 static char *szMachineName      = "ComputerName";
78 static void (PMAPIP fatalErrorCleanup)(void) = NULL;
79
80 /*----------------------------- Implementation ----------------------------*/
81
82 /* Functions to read and write CMOS registers */
83
84 ulong   PMAPI _PM_getPDB(void);
85 uchar   PMAPI _PM_readCMOS(int index);
86 void    PMAPI _PM_writeCMOS(int index,uchar value);
87
88 /****************************************************************************
89 REMARKS:
90 PM_malloc override function for Nucleus drivers loaded in VxD's.
91 ****************************************************************************/
92 void * VXD_malloc(
93     size_t size)
94 {
95     return PM_mallocShared(size);
96 }
97
98 /****************************************************************************
99 REMARKS:
100 PM_calloc override function for Nucleus drivers loaded in VxD's.
101 ****************************************************************************/
102 void * VXD_calloc(
103     size_t nelem,
104     size_t size)
105 {
106     void *p = PM_mallocShared(nelem * size);
107     if (p)
108         memset(p,0,nelem * size);
109     return p;
110 }
111
112 /****************************************************************************
113 REMARKS:
114 PM_realloc override function for Nucleus drivers loaded in VxD's.
115 ****************************************************************************/
116 void * VXD_realloc(
117     void *ptr,
118     size_t size)
119 {
120     void *p = PM_mallocShared(size);
121     if (p) {
122         memcpy(p,ptr,size);
123         PM_freeShared(ptr);
124         }
125     return p;
126 }
127
128 /****************************************************************************
129 REMARKS:
130 PM_free override function for Nucleus drivers loaded in VxD's.
131 ****************************************************************************/
132 void VXD_free(
133     void *p)
134 {
135     PM_freeShared(p);
136 }
137
138 /****************************************************************************
139 REMARKS:
140 Initialise the PM library.
141 ****************************************************************************/
142 void PMAPI PM_init(void)
143 {
144     /* Override the default memory allocators for all Nucleus drivers
145      * loaded in SDDHELP/PMHELP. We do this so that we can ensure all memory
146      * dynamically allocated by Nucleus drivers and internal C runtime
147      * library functions are shared memory blocks that all processes
148      * connecting to SDDHELP can see.
149      */
150     PM_useLocalMalloc(VXD_malloc,VXD_calloc,VXD_realloc,VXD_free);
151
152     /* Initialiase the MTRR module */
153     MTRR_init();
154 }
155
156 ibool PMAPI PM_haveBIOSAccess(void)
157 { return _PM_haveBIOS; }
158
159 long PMAPI PM_getOSType(void)
160 { return _OS_WIN32VXD; }
161
162 int PMAPI PM_getModeType(void)
163 { return PM_386; }
164
165 void PMAPI PM_backslash(char *s)
166 {
167     uint pos = strlen(s);
168     if (s[pos-1] != '\\') {
169         s[pos] = '\\';
170         s[pos+1] = '\0';
171         }
172 }
173
174 void PMAPI PM_setFatalErrorCleanup(
175     void (PMAPIP cleanup)(void))
176 {
177     fatalErrorCleanup = cleanup;
178 }
179
180 void PMAPI PM_fatalError(const char *msg)
181 {
182     if (fatalErrorCleanup)
183         fatalErrorCleanup();
184     Fatal_Error_Handler(msg,0);
185 }
186
187 /****************************************************************************
188 PARAMETERS:
189 len     - Place to store the length of the buffer
190 rseg    - Place to store the real mode segment of the buffer
191 roff    - Place to store the real mode offset of the buffer
192
193 REMARKS:
194 This function returns the address and length of the global VESA transfer
195 buffer that is used for communicating with the VESA BIOS functions from
196 Win16 and Win32 programs under Windows.
197 ****************************************************************************/
198 void * PMAPI PM_getVESABuf(
199     uint *len,
200     uint *rseg,
201     uint *roff)
202 {
203     /* If the VxD is dynamically loaded we will not have a real mode
204      * transfer buffer to return, so we fail the call.
205      */
206     if (_PM_rmBufAddr) {
207         *len = VESA_BUF_SIZE;
208         *rseg = (ulong)(_PM_rmBufAddr) >> 4;
209         *roff = (ulong)(_PM_rmBufAddr) & 0xF;
210         return _PM_rmBufAddr;
211         }
212     return NULL;
213 }
214
215 int PMAPI PM_int386(
216     int intno,
217     PMREGS *in,
218     PMREGS *out)
219 {
220     /* Unused in VxDs */
221     return 0;
222 }
223
224 void PMAPI _PM_getRMvect(
225     int intno,
226     long *realisr)
227 {
228     WORD    seg;
229     DWORD   off;
230
231     Get_V86_Int_Vector(intno,&seg,&off);
232     *realisr = ((long)seg << 16) | (off & 0xFFFF);
233 }
234
235 void PMAPI _PM_setRMvect(
236     int intno,
237     long realisr)
238 {
239     Set_V86_Int_Vector(intno,realisr >> 16,realisr & 0xFFFF);
240 }
241
242 char * PMAPI PM_getCurrentPath(
243     char *path,
244     int maxLen)
245 {
246     strncpy(path,_PM_cntPath,maxLen);
247     path[maxLen-1] = 0;
248     return path;
249 }
250
251 char PMAPI PM_getBootDrive(void)
252 { return 'c'; }
253
254 const char * PMAPI PM_getVBEAFPath(void)
255 { return "c:\\"; }
256
257 /****************************************************************************
258 PARAMETERS:
259 szKey       - Key to query (can contain version number formatting)
260 szValue     - Value to get information for
261 value       - Place to store the registry key data read
262 size        - Size of the string buffer to read into
263
264 RETURNS:
265 true if the key was found, false if not.
266 ****************************************************************************/
267 static ibool REG_queryString(
268     char *szKey,
269     char *szValue,
270     char *value,
271     ulong size)
272 {
273     HKEY    hKey;
274     ulong   type;
275     ibool   status = false;
276
277     memset(value,0,sizeof(value));
278     if (RegOpenKey(HKEY_LOCAL_MACHINE,szKey,&hKey) == ERROR_SUCCESS) {
279         if (RegQueryValueEx(hKey,(PCHAR)szValue,(ulong*)NULL,(ulong*)&type,value,(ulong*)&size) == ERROR_SUCCESS)
280             status = true;
281         RegCloseKey(hKey);
282         }
283     return status;
284 }
285
286 const char * PMAPI PM_getNucleusPath(void)
287 {
288     static char path[256];
289
290     if (strlen(_PM_nucleusPath) > 0) {
291         strcpy(path,_PM_nucleusPath);
292         PM_backslash(path);
293         return path;
294         }
295     if (!REG_queryString(szWindowsKey,szSystemRoot,path,sizeof(path)))
296         strcpy(path,"c:\\windows");
297     PM_backslash(path);
298     strcat(path,"system\\nucleus");
299     return path;
300 }
301
302 const char * PMAPI PM_getNucleusConfigPath(void)
303 {
304     static char path[256];
305     strcpy(path,PM_getNucleusPath());
306     PM_backslash(path);
307     strcat(path,"config");
308     return path;
309 }
310
311 const char * PMAPI PM_getUniqueID(void)
312 { return PM_getMachineName(); }
313
314 const char * PMAPI PM_getMachineName(void)
315 {
316     static char name[256];
317     if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name)))
318         return name;
319     return "Unknown";
320 }
321
322 int PMAPI PM_kbhit(void)
323 { return 1; }
324
325 int PMAPI PM_getch(void)
326 { return 0; }
327
328 PM_HWND PMAPI PM_openConsole(
329     PM_HWND hwndUser,
330     int device,
331     int xRes,
332     int yRes,
333     int bpp,
334     ibool fullScreen)
335 {
336     /* Unused in VxDs */
337     return NULL;
338 }
339
340 int PMAPI PM_getConsoleStateSize(void)
341 {
342     /* Unused in VxDs */
343     return 1;
344 }
345
346 void PMAPI PM_saveConsoleState(
347     void *stateBuf,
348     PM_HWND hwndConsole)
349 {
350     /* Unused in VxDs */
351 }
352
353 void PMAPI PM_setSuspendAppCallback(
354     int (_ASMAPIP saveState)(
355         int flags))
356 {
357     /* Unused in VxDs */
358 }
359
360 void PMAPI PM_restoreConsoleState(
361     const void *stateBuf,
362     PM_HWND hwndConsole)
363 {
364     /* Unused in VxDs */
365 }
366
367 void PMAPI PM_closeConsole(
368     PM_HWND hwndConsole)
369 {
370     /* Unused in VxDs */
371 }
372
373 void PM_setOSCursorLocation(
374     int x,
375     int y)
376 {
377     uchar *_biosPtr = PM_getBIOSPointer();
378     PM_setByte(_biosPtr+0x50,x);
379     PM_setByte(_biosPtr+0x51,y);
380 }
381
382 void PM_setOSScreenWidth(
383     int width,
384     int height)
385 {
386     uchar *_biosPtr = PM_getBIOSPointer();
387     PM_setByte(_biosPtr+0x4A,width);
388     PM_setByte(_biosPtr+0x84,height-1);
389 }
390
391 /****************************************************************************
392 REMARKS:
393 Allocate a block of shared memory. For Win9x we allocate shared memory
394 as locked, global memory that is accessible from any memory context
395 (including interrupt time context), which allows us to load our important
396 data structure and code such that we can access it directly from a ring
397 0 interrupt context.
398 ****************************************************************************/
399 void * PMAPI PM_mallocShared(
400     long size)
401 {
402     MEMHANDLE   hMem;
403     DWORD       pgNum,nPages = (size + 0xFFF) >> 12;
404     int         i;
405
406     /* First find a free slot in our shared memory table */
407     for (i = 0; i < MAX_MEMORY_SHARED; i++) {
408         if (shared[i].linear == 0)
409             break;
410         }
411     if (i < MAX_MEMORY_SHARED) {
412         PageAllocate(nPages,PG_SYS,0,0,0,0,NULL,0,&hMem,&shared[i].linear);
413         shared[i].npages = nPages;
414         pgNum = (ulong)shared[i].linear >> 12;
415         shared[i].global = LinPageLock(pgNum,nPages,PAGEMAPGLOBAL);
416         return (void*)shared[i].global;
417         }
418     return NULL;
419 }
420
421 /****************************************************************************
422 REMARKS:
423 Free a block of shared memory
424 ****************************************************************************/
425 void PMAPI PM_freeShared(void *p)
426 {
427     int i;
428
429     /* Find a shared memory block in our table and free it */
430     for (i = 0; i < MAX_MEMORY_SHARED; i++) {
431         if (shared[i].global == (ulong)p) {
432             LinPageUnLock(shared[i].global >> 12,shared[i].npages,PAGEMAPGLOBAL);
433             PageFree((ulong)shared[i].linear,0);
434             shared[i].linear = 0;
435             break;
436             }
437         }
438 }
439
440 /****************************************************************************
441 REMARKS:
442 Maps a shared memory block into process address space. Does nothing since
443 the memory blocks are already globally7 mapped into all processes.
444 ****************************************************************************/
445 void * PMAPI PM_mapToProcess(
446     void *base,
447     ulong limit)
448 {
449     return (void*)base;
450 }
451
452 ibool PMAPI PM_doBIOSPOST(
453     ushort axVal,
454     ulong BIOSPhysAddr,
455     void *mappedBIOS,
456     ulong BIOSLen)
457 {
458     // TODO: Figure out how to do this
459     return false;
460 }
461
462 void * PMAPI PM_getBIOSPointer(void)
463 { return (void*)0x400; }
464
465 void * PMAPI PM_getA0000Pointer(void)
466 { return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
467
468 /****************************************************************************
469 PARAMETERS:
470 base        - Physical base address of the memory to maps in
471 limit       - Limit of physical memory to region to maps in
472
473 RETURNS:
474 Linear address of the newly mapped memory.
475
476 REMARKS:
477 Maps a physical memory range to a linear memory range.
478 ****************************************************************************/
479 ulong _PM_mapPhysicalToLinear(
480     ulong base,
481     ulong limit,
482     int *npages)
483 {
484     ulong   linear,length = limit+1;
485     int     i,ppage,flags;
486
487     if (base < 0x100000) {
488         /* Windows 9x is zero based for the first meg of memory */
489         return base;
490         }
491     ppage = base >> 12;
492     *npages = (length + (base & 0xFFF) + 4095) >> 12;
493     flags = PR_FIXED | PR_STATIC;
494     if (base == 0xA0000) {
495         /* We require the linear address to be aligned to a 64Kb boundary
496          * for mapping the banked framebuffer (so we can do efficient
497          * carry checking for bank changes in the assembler code). The only
498          * way to ensure this is to force the linear address to be aligned
499          * to a 4Mb boundary.
500          */
501         flags |= PR_4MEG;
502         }
503     if ((linear = (ulong)PageReserve(PR_SYSTEM,*npages,flags)) == (ulong)-1)
504         return 0xFFFFFFFF;
505     if (!PageCommitPhys(linear >> 12,*npages,ppage,PC_INCR | PC_USER | PC_WRITEABLE))
506         return 0xFFFFFFFF;
507     return linear + (base & 0xFFF);
508 }
509
510 // Page table flags
511
512 #define PAGE_FLAGS_PRESENT                      0x00000001
513 #define PAGE_FLAGS_WRITEABLE            0x00000002
514 #define PAGE_FLAGS_USER                         0x00000004
515 #define PAGE_FLAGS_WRITE_THROUGH        0x00000008
516 #define PAGE_FLAGS_CACHE_DISABLE        0x00000010
517 #define PAGE_FLAGS_ACCESSED                     0x00000020
518 #define PAGE_FLAGS_DIRTY                        0x00000040
519 #define PAGE_FLAGS_4MB              0x00000080
520
521 /****************************************************************************
522 PARAMETERS:
523 base        - Physical base address of the memory to maps in
524 limit       - Limit of physical memory to region to maps in
525 isCached    - True if the memory should be cached, false if not
526
527 RETURNS:
528 Linear address of the newly mapped memory.
529
530 REMARKS:
531 This function maps physical memory to linear memory, which can then be used
532 to create a selector or used directly from 32-bit protected mode programs.
533 This is better than DPMI 0x800, since it allows you to maps physical
534 memory below 1Mb, which gets this memory out of the way of the Windows VDD's
535 sticky paws.
536
537 NOTE:   If the memory is not expected to be cached, this function will
538         directly re-program the PCD (Page Cache Disable) bit in the
539         page tables. There does not appear to be a mechanism in the VMM
540         to control this bit via the regular interface.
541 ****************************************************************************/
542 void * PMAPI PM_mapPhysicalAddr(
543     ulong base,
544     ulong limit,
545     ibool isCached)
546 {
547     ulong   linear,length = limit+1;
548     int     i,npages;
549     ulong   PDB,*pPDB;
550
551     /* Search table of existing mappings to see if we have already mapped
552      * a region of memory that will serve this purpose.
553      */
554     for (i = 0; i < numMappings; i++) {
555         if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached)
556             return (void*)maps[i].linear;
557         }
558     if (numMappings == MAX_MEMORY_MAPPINGS)
559         return NULL;
560
561     /* We did not find any previously mapped memory region, so maps it in.
562      * Note that we do not use MapPhysToLinear, since this function appears
563      * to have problems mapping memory in the 1Mb physical address space.
564      * Hence we use PageReserve and PageCommitPhys.
565      */
566     if ((linear = _PM_mapPhysicalToLinear(base,limit,&npages)) == 0xFFFFFFFF)
567         return NULL;
568     maps[numMappings].physical = base;
569     maps[numMappings].length = length;
570     maps[numMappings].linear = linear;
571     maps[numMappings].npages = npages;
572     maps[numMappings].isCached = isCached;
573     numMappings++;
574
575     /* Finally disable caching where necessary */
576     if (!isCached && (PDB = _PM_getPDB()) != 0) {
577         int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
578         ulong   pageTable,*pPageTable;
579         pPDB = (ulong*)_PM_mapPhysicalToLinear(PDB,0xFFF,&npages);
580         if (pPDB) {
581             startPDB = (linear >> 22) & 0x3FF;
582             startPage = (linear >> 12) & 0x3FF;
583             endPDB = ((linear+limit) >> 22) & 0x3FF;
584             endPage = ((linear+limit) >> 12) & 0x3FF;
585             for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
586                 // Set the bits in the page directory entry - required as per
587                 // Pentium 4 manual. This also takes care of the 4MB page entries
588                 pPDB[iPDB] = pPDB[iPDB] |= (PAGE_FLAGS_WRITE_THROUGH | PAGE_FLAGS_CACHE_DISABLE);
589                 if (!(pPDB[iPDB] & PAGE_FLAGS_4MB)) {
590                     // If we are dealing with 4KB pages then we need to iterate
591                     // through each of the page table entries
592                     pageTable = pPDB[iPDB] & ~0xFFF;
593                     pPageTable = (ulong*)_PM_mapPhysicalToLinear(pageTable,0xFFF,&npages);
594                     start = (iPDB == startPDB) ? startPage : 0;
595                     end = (iPDB == endPDB) ? endPage : 0x3FF;
596                     for (iPage = start; iPage <= end; iPage++)
597                         pPageTable[iPage] |= (PAGE_FLAGS_WRITE_THROUGH | PAGE_FLAGS_CACHE_DISABLE);
598                     PageFree((ulong)pPageTable,PR_STATIC);
599                     }
600                 }
601             PageFree((ulong)pPDB,PR_STATIC);
602             PM_flushTLB();
603             }
604         }
605     return (void*)linear;
606 }
607
608 void PMAPI PM_freePhysicalAddr(
609     void *ptr,
610     ulong limit)
611 {
612     /* We never free the mappings */
613 }
614
615 void PMAPI PM_sleep(ulong milliseconds)
616 {
617     /* We never sleep in a VxD */
618 }
619
620 int PMAPI PM_getCOMPort(int port)
621 {
622     // TODO: Re-code this to determine real values using the Plug and Play
623     //       manager for the OS.
624     switch (port) {
625         case 0: return 0x3F8;
626         case 1: return 0x2F8;
627         case 2: return 0x3E8;
628         case 3: return 0x2E8;
629         }
630     return 0;
631 }
632
633 int PMAPI PM_getLPTPort(int port)
634 {
635     // TODO: Re-code this to determine real values using the Plug and Play
636     //       manager for the OS.
637     switch (port) {
638         case 0: return 0x3BC;
639         case 1: return 0x378;
640         case 2: return 0x278;
641         }
642     return 0;
643 }
644
645 ulong PMAPI PM_getPhysicalAddr(
646     void *p)
647 {
648     DWORD   pte;
649
650     // Touch the memory before calling CopyPageTable. For some reason
651     // we need to do this on Windows 9x, otherwise the memory may not
652     // be paged in correctly. Of course if the passed in pointer is
653     // invalid, this function will fault, but we shouldn't be passed bogus
654     // pointers anyway ;-)
655     pte = *((ulong*)p);
656
657     // Return assembled address value only if VMM service succeeds
658     if (CopyPageTable(((DWORD)p) >> 12, 1, (PVOID*)&pte, 0))
659         return (pte & ~0xFFF) | (((DWORD)p) & 0xFFF);
660
661     // Return failure to the caller!
662     return 0xFFFFFFFFUL;
663 }
664
665 ibool PMAPI PM_getPhysicalAddrRange(
666     void *p,
667     ulong length,
668     ulong *physAddress)
669 {
670     int     i;
671     ulong   linear = (ulong)p & ~0xFFF;
672
673     for (i = (length + 0xFFF) >> 12; i > 0; i--) {
674         if ((*physAddress++ = PM_getPhysicalAddr((void*)linear)) == 0xFFFFFFFF)
675             return false;
676         linear += 4096;
677         }
678     return true;
679 }
680
681 void PMAPI _PM_freeMemoryMappings(void)
682 {
683     int i;
684     for (i = 0; i < numMappings; i++)
685         PageFree(maps[i].linear,PR_STATIC);
686 }
687
688 void * PMAPI PM_mapRealPointer(
689     uint r_seg,
690     uint r_off)
691 {
692     return (void*)MK_PHYS(r_seg,r_off);
693 }
694
695 void * PMAPI PM_allocRealSeg(
696     uint size,
697     uint *r_seg,
698     uint *r_off)
699 {
700     return NULL;
701 }
702
703 void PMAPI PM_freeRealSeg(
704     void *mem)
705 {
706 }
707
708 void PMAPI DPMI_int86(
709     int intno,
710     DPMI_regs *regs)
711 {
712     /* Unsed in VxD's */
713 }
714
715 /****************************************************************************
716 REMARKS:
717 Load the V86 registers in the client state, and save the original state
718 before loading the registers.
719 ****************************************************************************/
720 static void LoadV86Registers(
721     CLIENT_STRUCT *saveRegs,
722     RMREGS *in,
723     RMSREGS *sregs)
724 {
725     CLIENT_STRUCT   newRegs;
726
727     Save_Client_State(saveRegs);
728     newRegs = *saveRegs;
729     newRegs.CRS.Client_EAX = in->e.eax;
730     newRegs.CRS.Client_EBX = in->e.ebx;
731     newRegs.CRS.Client_ECX = in->e.ecx;
732     newRegs.CRS.Client_EDX = in->e.edx;
733     newRegs.CRS.Client_ESI = in->e.esi;
734     newRegs.CRS.Client_EDI = in->e.edi;
735     newRegs.CRS.Client_ES = sregs->es;
736     newRegs.CRS.Client_DS = sregs->ds;
737     Restore_Client_State(&newRegs);
738 }
739
740 /****************************************************************************
741 REMARKS:
742 Read the V86 registers from the client state and restore the original state.
743 ****************************************************************************/
744 static void ReadV86Registers(
745     CLIENT_STRUCT *saveRegs,
746     RMREGS *out,
747     RMSREGS *sregs)
748 {
749     CLIENT_STRUCT   newRegs;
750
751     Save_Client_State(&newRegs);
752     out->e.eax = newRegs.CRS.Client_EAX;
753     out->e.ebx = newRegs.CRS.Client_EBX;
754     out->e.ecx = newRegs.CRS.Client_ECX;
755     out->e.edx = newRegs.CRS.Client_EDX;
756     out->e.esi = newRegs.CRS.Client_ESI;
757     out->e.edi = newRegs.CRS.Client_EDI;
758     sregs->es = newRegs.CRS.Client_ES;
759     sregs->ds = newRegs.CRS.Client_DS;
760     Restore_Client_State(saveRegs);
761 }
762
763 /****************************************************************************
764 REMARKS:
765 Call a V86 real mode function with the specified register values
766 loaded before the call. The call returns with a far ret.
767 ****************************************************************************/
768 void PMAPI PM_callRealMode(
769     uint seg,
770     uint off,
771     RMREGS *regs,
772     RMSREGS *sregs)
773 {
774     CLIENT_STRUCT saveRegs;
775
776     /* Bail if we do not have BIOS access (ie: the VxD was dynamically
777      * loaded, and not statically loaded.
778      */
779     if (!_PM_haveBIOS)
780         return;
781
782     _TRACE("SDDHELP: Entering PM_callRealMode()\n");
783     Begin_Nest_V86_Exec();
784     LoadV86Registers(&saveRegs,regs,sregs);
785     Simulate_Far_Call(seg, off);
786     Resume_Exec();
787     ReadV86Registers(&saveRegs,regs,sregs);
788     End_Nest_Exec();
789     _TRACE("SDDHELP: Exiting PM_callRealMode()\n");
790 }
791
792 /****************************************************************************
793 REMARKS:
794 Issue a V86 real mode interrupt with the specified register values
795 loaded before the interrupt.
796 ****************************************************************************/
797 int PMAPI PM_int86(
798     int intno,
799     RMREGS *in,
800     RMREGS *out)
801 {
802     RMSREGS         sregs = {0};
803     CLIENT_STRUCT   saveRegs;
804     ushort          oldDisable;
805
806     /* Bail if we do not have BIOS access (ie: the VxD was dynamically
807      * loaded, and not statically loaded.
808      */
809     if (!_PM_haveBIOS) {
810         *out = *in;
811         return out->x.ax;
812         }
813
814     /* Disable pass-up to our VxD handler so we directly call BIOS */
815     _TRACE("SDDHELP: Entering PM_int86()\n");
816     if (disableTSRFlag) {
817         oldDisable = *disableTSRFlag;
818         *disableTSRFlag = 0;
819         }
820     Begin_Nest_V86_Exec();
821     LoadV86Registers(&saveRegs,in,&sregs);
822     Exec_Int(intno);
823     ReadV86Registers(&saveRegs,out,&sregs);
824     End_Nest_Exec();
825
826     /* Re-enable pass-up to our VxD handler if previously enabled */
827     if (disableTSRFlag)
828         *disableTSRFlag = oldDisable;
829
830     _TRACE("SDDHELP: Exiting PM_int86()\n");
831     return out->x.ax;
832 }
833
834 /****************************************************************************
835 REMARKS:
836 Issue a V86 real mode interrupt with the specified register values
837 loaded before the interrupt.
838 ****************************************************************************/
839 int PMAPI PM_int86x(
840     int intno,
841     RMREGS *in,
842     RMREGS *out,
843     RMSREGS *sregs)
844 {
845     CLIENT_STRUCT   saveRegs;
846     ushort          oldDisable;
847
848     /* Bail if we do not have BIOS access (ie: the VxD was dynamically
849      * loaded, and not statically loaded.
850      */
851     if (!_PM_haveBIOS) {
852         *out = *in;
853         return out->x.ax;
854         }
855
856     /* Disable pass-up to our VxD handler so we directly call BIOS */
857     _TRACE("SDDHELP: Entering PM_int86x()\n");
858     if (disableTSRFlag) {
859         oldDisable = *disableTSRFlag;
860         *disableTSRFlag = 0;
861         }
862     Begin_Nest_V86_Exec();
863     LoadV86Registers(&saveRegs,in,sregs);
864     Exec_Int(intno);
865     ReadV86Registers(&saveRegs,out,sregs);
866     End_Nest_Exec();
867
868     /* Re-enable pass-up to our VxD handler if previously enabled */
869     if (disableTSRFlag)
870         *disableTSRFlag = oldDisable;
871
872     _TRACE("SDDHELP: Exiting PM_int86x()\n");
873     return out->x.ax;
874 }
875
876 /****************************************************************************
877 REMARKS:
878 Returns available memory. Not possible under Windows.
879 ****************************************************************************/
880 void PMAPI PM_availableMemory(
881     ulong *physical,
882     ulong *total)
883 {
884     *physical = *total = 0;
885 }
886
887 /****************************************************************************
888 REMARKS:
889 Allocates a block of locked physical memory.
890 ****************************************************************************/
891 void * PMAPI PM_allocLockedMem(
892     uint size,
893     ulong *physAddr,
894     ibool contiguous,
895     ibool below16M)
896 {
897     MEMHANDLE   hMem;
898     DWORD       nPages = (size + 0xFFF) >> 12;
899     DWORD       flags = PAGEFIXED | PAGEUSEALIGN | (contiguous ? PAGECONTIG : 0);
900     DWORD       maxPhys = below16M ? 0x00FFFFFF : 0xFFFFFFFF;
901     void        *p;
902
903     // TODO: This may need to be modified if the memory needs to be globally
904     //       accessible. Check how we implemented PM_mallocShared() as we
905     //       may need to do something similar in here.
906     PageAllocate(nPages,PG_SYS,0,0,0,maxPhys,physAddr,flags,&hMem,&p);
907
908     // TODO: We may need to modify the memory blocks to disable caching via
909     //       the page tables (PCD|PWT) since DMA memory blocks *cannot* be
910     //       cached!
911     return p;
912 }
913
914 /****************************************************************************
915 REMARKS:
916 Frees a block of locked physical memory.
917 ****************************************************************************/
918 void PMAPI PM_freeLockedMem(
919     void *p,
920     uint size,
921     ibool contiguous)
922 {
923     if (p)
924         PageFree((ulong)p,0);
925 }
926
927 /****************************************************************************
928 REMARKS:
929 Allocates a page aligned and page sized block of memory
930 ****************************************************************************/
931 void * PMAPI PM_allocPage(
932     ibool locked)
933 {
934     MEMHANDLE   hMem;
935     void        *p;
936
937     // TODO: This will need to be modified if the memory needs to be globally
938     //       accessible. Check how we implemented PM_mallocShared() as we
939     //       may need to do something similar in here.
940     PageAllocate(1,PG_SYS,0,0,0,0,0,PAGEFIXED,&hMem,&p);
941     return p;
942 }
943
944 /****************************************************************************
945 REMARKS:
946 Free a page aligned and page sized block of memory
947 ****************************************************************************/
948 void PMAPI PM_freePage(
949     void *p)
950 {
951     if (p)
952         PageFree((ulong)p,0);
953 }
954
955 /****************************************************************************
956 REMARKS:
957 Lock linear memory so it won't be paged.
958 ****************************************************************************/
959 int PMAPI PM_lockDataPages(
960     void *p,
961     uint len,
962     PM_lockHandle *lh)
963 {
964     DWORD pgNum = (ulong)p >> 12;
965     DWORD nPages = (len + (ulong)p - (pgNum << 12) + 0xFFF) >> 12;
966     return LinPageLock(pgNum,nPages,0);
967 }
968
969 /****************************************************************************
970 REMARKS:
971 Unlock linear memory so it won't be paged.
972 ****************************************************************************/
973 int PMAPI PM_unlockDataPages(
974     void *p,
975     uint len,
976     PM_lockHandle *lh)
977 {
978     DWORD pgNum = (ulong)p >> 12;
979     DWORD nPages = (len + (ulong)p - (pgNum << 12) + 0xFFF) >> 12;
980     return LinPageUnLock(pgNum,nPages,0);
981 }
982
983 /****************************************************************************
984 REMARKS:
985 Lock linear memory so it won't be paged.
986 ****************************************************************************/
987 int PMAPI PM_lockCodePages(
988     void (*p)(),
989     uint len,
990     PM_lockHandle *lh)
991 {
992     return PM_lockDataPages((void*)p,len,lh);
993 }
994
995 /****************************************************************************
996 REMARKS:
997 Unlock linear memory so it won't be paged.
998 ****************************************************************************/
999 int PMAPI PM_unlockCodePages(
1000     void (*p)(),
1001     uint len,
1002     PM_lockHandle *lh)
1003 {
1004     return PM_unlockDataPages((void*)p,len,lh);
1005 }
1006
1007 /****************************************************************************
1008 REMARKS:
1009 Set the real time clock frequency (for stereo modes).
1010 ****************************************************************************/
1011 void PMAPI PM_setRealTimeClockFrequency(
1012     int frequency)
1013 {
1014     static short convert[] = {
1015         8192,
1016         4096,
1017         2048,
1018         1024,
1019         512,
1020         256,
1021         128,
1022         64,
1023         32,
1024         16,
1025         8,
1026         4,
1027         2,
1028         -1,
1029         };
1030     int i;
1031
1032     /* First clear any pending RTC timeout if not cleared */
1033     _PM_readCMOS(0x0C);
1034     if (frequency == 0) {
1035         /* Disable RTC timout */
1036         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
1037         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
1038         }
1039     else {
1040         /* Convert frequency value to RTC clock indexes */
1041         for (i = 0; convert[i] != -1; i++) {
1042             if (convert[i] == frequency)
1043                 break;
1044             }
1045
1046         /* Set RTC timout value and enable timeout */
1047         _PM_writeCMOS(0x0A,0x20 | (i+3));
1048         _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
1049         }
1050 }
1051
1052 /****************************************************************************
1053 REMARKS:
1054 Real time clock interrupt handler, which calls the user registered C code.
1055 ****************************************************************************/
1056 static BOOL __stdcall RTCInt_Handler(
1057     VMHANDLE hVM,
1058     IRQHANDLE hIRQ)
1059 {
1060     static char inside = 0;
1061
1062     /* Clear priority interrupt controller and re-enable interrupts so we
1063      * dont lock things up for long.
1064      */
1065     VPICD_Phys_EOI(hIRQ);
1066
1067     /* Clear real-time clock timeout */
1068     _PM_readCMOS(0x0C);
1069
1070     /* Now call the C based interrupt handler (but check for mutual
1071      * exclusion since we may still be servicing an old interrupt when a
1072      * new one comes along; if that happens we ignore the old one).
1073      */
1074     if (!inside) {
1075         inside = 1;
1076         enable();
1077         _PM_rtcHandler();
1078         inside = 0;
1079         }
1080     return TRUE;
1081 }
1082
1083 /****************************************************************************
1084 REMARKS:
1085 Set the real time clock handler (used for software stereo modes).
1086 ****************************************************************************/
1087 ibool PMAPI PM_setRealTimeClockHandler(
1088     PM_intHandler ih,
1089     int frequency)
1090 {
1091     struct VPICD_IRQ_Descriptor IRQdesc;
1092
1093     /* Save the old CMOS real time clock values */
1094     _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
1095     _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
1096
1097     /* Set the real time clock interrupt handler */
1098     CHECK(ih != NULL);
1099     _PM_rtcHandler = ih;
1100     IRQdesc.VID_IRQ_Number      = 0x8;
1101     IRQdesc.VID_Options         = 0;
1102     IRQdesc.VID_Hw_Int_Proc     = (DWORD)VPICD_Thunk_HWInt(RTCInt_Handler, &RTCInt_Thunk);
1103     IRQdesc.VID_EOI_Proc        = 0;
1104     IRQdesc.VID_Virt_Int_Proc   = 0;
1105     IRQdesc.VID_Mask_Change_Proc= 0;
1106     IRQdesc.VID_IRET_Proc       = 0;
1107     IRQdesc.VID_IRET_Time_Out   = 500;
1108     if ((RTCIRQHandle = VPICD_Virtualize_IRQ(&IRQdesc)) == 0)
1109         return false;
1110
1111     /* Program the real time clock default frequency */
1112     PM_setRealTimeClockFrequency(frequency);
1113
1114     /* Unmask IRQ8 in the PIC */
1115     VPICD_Physically_Unmask(RTCIRQHandle);
1116     return true;
1117 }
1118
1119 /****************************************************************************
1120 REMARKS:
1121 Restore the original real time clock handler.
1122 ****************************************************************************/
1123 void PMAPI PM_restoreRealTimeClockHandler(void)
1124 {
1125     if (RTCIRQHandle) {
1126         /* Restore CMOS registers and mask RTC clock */
1127         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
1128         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
1129
1130         /* Restore the interrupt vector */
1131         VPICD_Set_Auto_Masking(RTCIRQHandle);
1132         VPICD_Force_Default_Behavior(RTCIRQHandle);
1133         RTCIRQHandle = 0;
1134         }
1135 }
1136
1137 /****************************************************************************
1138 REMARKS:
1139 OS specific shared libraries not supported inside a VxD
1140 ****************************************************************************/
1141 PM_MODULE PMAPI PM_loadLibrary(
1142     const char *szDLLName)
1143 {
1144     (void)szDLLName;
1145     return NULL;
1146 }
1147
1148 /****************************************************************************
1149 REMARKS:
1150 OS specific shared libraries not supported inside a VxD
1151 ****************************************************************************/
1152 void * PMAPI PM_getProcAddress(
1153     PM_MODULE hModule,
1154     const char *szProcName)
1155 {
1156     (void)hModule;
1157     (void)szProcName;
1158     return NULL;
1159 }
1160
1161 /****************************************************************************
1162 REMARKS:
1163 OS specific shared libraries not supported inside a VxD
1164 ****************************************************************************/
1165 void PMAPI PM_freeLibrary(
1166     PM_MODULE hModule)
1167 {
1168     (void)hModule;
1169 }
1170
1171 /****************************************************************************
1172 REMARKS:
1173 Function to find the first file matching a search criteria in a directory.
1174 ****************************************************************************/
1175 void *PMAPI PM_findFirstFile(
1176     const char *filename,
1177     PM_findData *findData)
1178 {
1179     // TODO: This function should start a directory enumeration search
1180     //       given the filename (with wildcards). The data should be
1181     //       converted and returned in the findData standard form.
1182     (void)filename;
1183     (void)findData;
1184     return PM_FILE_INVALID;
1185 }
1186
1187 /****************************************************************************
1188 REMARKS:
1189 Function to find the next file matching a search criteria in a directory.
1190 ****************************************************************************/
1191 ibool PMAPI PM_findNextFile(
1192     void *handle,
1193     PM_findData *findData)
1194 {
1195     // TODO: This function should find the next file in directory enumeration
1196     //       search given the search criteria defined in the call to
1197     //       PM_findFirstFile. The data should be converted and returned
1198     //       in the findData standard form.
1199     (void)handle;
1200     (void)findData;
1201     return false;
1202 }
1203
1204 /****************************************************************************
1205 REMARKS:
1206 Function to close the find process
1207 ****************************************************************************/
1208 void PMAPI PM_findClose(
1209     void *handle)
1210 {
1211     // TODO: This function should close the find process. This may do
1212     //       nothing for some OS'es.
1213     (void)handle;
1214 }
1215
1216 /****************************************************************************
1217 REMARKS:
1218 Function to determine if a drive is a valid drive or not. Under Unix this
1219 function will return false for anything except a value of 3 (considered
1220 the root drive, and equivalent to C: for non-Unix systems). The drive
1221 numbering is:
1222
1223     1   - Drive A:
1224     2   - Drive B:
1225     3   - Drive C:
1226     etc
1227
1228 ****************************************************************************/
1229 ibool PMAPI PM_driveValid(
1230     char drive)
1231 {
1232     // Not supported in a VxD
1233     (void)drive;
1234     return false;
1235 }
1236
1237 /****************************************************************************
1238 REMARKS:
1239 Function to get the current working directory for the specififed drive.
1240 Under Unix this will always return the current working directory regardless
1241 of what the value of 'drive' is.
1242 ****************************************************************************/
1243 void PMAPI PM_getdcwd(
1244     int drive,
1245     char *dir,
1246     int len)
1247 {
1248     // Not supported in a VxD
1249     (void)drive;
1250     (void)dir;
1251     (void)len;
1252 }
1253
1254 /****************************************************************************
1255 PARAMETERS:
1256 base    - The starting physical base address of the region
1257 size    - The size in bytes of the region
1258 type    - Type to place into the MTRR register
1259
1260 RETURNS:
1261 Error code describing the result.
1262
1263 REMARKS:
1264 Function to enable write combining for the specified region of memory.
1265 ****************************************************************************/
1266 int PMAPI PM_enableWriteCombine(
1267     ulong base,
1268     ulong size,
1269     uint type)
1270 {
1271     return MTRR_enableWriteCombine(base,size,type);
1272 }
1273
1274 /****************************************************************************
1275 REMARKS:
1276 Function to change the file attributes for a specific file.
1277 ****************************************************************************/
1278 void PMAPI PM_setFileAttr(
1279     const char *filename,
1280     uint attrib)
1281 {
1282     // TODO: Implement this
1283     (void)filename;
1284     (void)attrib;
1285     PM_fatalError("PM_setFileAttr not implemented yet!");
1286 }
1287
1288 /****************************************************************************
1289 REMARKS:
1290 Function to get the file attributes for a specific file.
1291 ****************************************************************************/
1292 uint PMAPI PM_getFileAttr(
1293     const char *filename)
1294 {
1295     // TODO: Implement this
1296     (void)filename;
1297     PM_fatalError("PM_getFileAttr not implemented yet!");
1298     return 0;
1299 }
1300
1301 /****************************************************************************
1302 REMARKS:
1303 Function to create a directory.
1304 ****************************************************************************/
1305 ibool PMAPI PM_mkdir(
1306     const char *filename)
1307 {
1308     // TODO: Implement this
1309     (void)filename;
1310     PM_fatalError("PM_mkdir not implemented yet!");
1311     return false;
1312 }
1313
1314 /****************************************************************************
1315 REMARKS:
1316 Function to remove a directory.
1317 ****************************************************************************/
1318 ibool PMAPI PM_rmdir(
1319     const char *filename)
1320 {
1321     // TODO: Implement this
1322     (void)filename;
1323     PM_fatalError("PM_rmdir not implemented yet!");
1324     return false;
1325 }
1326
1327 /****************************************************************************
1328 REMARKS:
1329 Function to get the file time and date for a specific file.
1330 ****************************************************************************/
1331 ibool PMAPI PM_getFileTime(
1332     const char *filename,
1333     ibool gmTime,
1334     PM_time *time)
1335 {
1336     // TODO: Implement this!
1337     (void)filename;
1338     (void)gmTime;
1339     (void)time;
1340     PM_fatalError("PM_getFileTime not implemented yet!");
1341     return false;
1342 }
1343
1344 /****************************************************************************
1345 REMARKS:
1346 Function to set the file time and date for a specific file.
1347 ****************************************************************************/
1348 ibool PMAPI PM_setFileTime(
1349     const char *filename,
1350     ibool gmTime,
1351     PM_time *time)
1352 {
1353     // TODO: Implement this!
1354     (void)filename;
1355     (void)gmTime;
1356     (void)time;
1357     PM_fatalError("PM_setFileTime not implemented yet!");
1358     return false;
1359 }
1360