]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/smx/pm.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / smx / 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 SMX embedded systems development.
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 "ztimerc.h"
38 #include "event.h"
39 #include "mtrr.h"
40 #include "pm_help.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <dos.h>
45 #include <conio.h>
46 #ifdef  __GNUC__
47 #include <unistd.h>
48 #include <sys/nearptr.h>
49 #include <sys/stat.h>
50 #else
51 #include <direct.h>
52 #endif
53 #ifdef  __BORLANDC__
54 #pragma warn -par
55 #endif
56
57 /*--------------------------- Global variables ----------------------------*/
58
59 typedef struct {
60     int     oldMode;
61     int     old50Lines;
62     } DOS_stateBuf;
63
64 #define MAX_RM_BLOCKS   10
65
66 static struct {
67     void    *p;
68     uint    tag;
69     } rmBlocks[MAX_RM_BLOCKS];
70
71 static uint     VESABuf_len = 1024;     /* Length of the VESABuf buffer     */
72 static void     *VESABuf_ptr = NULL;    /* Near pointer to VESABuf          */
73 static uint     VESABuf_rseg;           /* Real mode segment of VESABuf     */
74 static uint     VESABuf_roff;           /* Real mode offset of VESABuf      */
75 static void     (PMAPIP fatalErrorCleanup)(void) = NULL;
76 ushort _VARAPI  _PM_savedDS = 0;
77 static ulong    PDB = 0,*pPDB = NULL;
78 static uint     VXD_version = -1;
79
80 /*----------------------------- Implementation ----------------------------*/
81
82 ulong   _ASMAPI _PM_getPDB(void);
83 void    _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel);
84
85 /****************************************************************************
86 REMARKS:
87 External function to call the PMHELP helper VxD.
88 ****************************************************************************/
89 void PMAPI PM_VxDCall(
90     VXD_regs *regs)
91 {
92 }
93
94 /****************************************************************************
95 RETURNS:
96 BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2)
97
98 REMARKS:
99 This function gets the version number for the VxD that we have connected to.
100 ****************************************************************************/
101 uint PMAPI PMHELP_getVersion(void)
102 {
103     return VXD_version = 0;
104 }
105
106 void PMAPI PM_init(void)
107 {
108 #ifndef REALMODE
109     MTRR_init();
110 #endif
111 }
112
113 /****************************************************************************
114 PARAMETERS:
115 base    - The starting physical base address of the region
116 size    - The size in bytes of the region
117 type    - Type to place into the MTRR register
118
119 RETURNS:
120 Error code describing the result.
121
122 REMARKS:
123 Function to enable write combining for the specified region of memory.
124 ****************************************************************************/
125 int PMAPI PM_enableWriteCombine(
126     ulong base,
127     ulong size,
128     uint type)
129 {
130 #ifndef REALMODE
131     return MTRR_enableWriteCombine(base,size,type);
132 #else
133     return PM_MTRR_NOT_SUPPORTED;
134 #endif
135 }
136
137 ibool PMAPI PM_haveBIOSAccess(void)
138 { return false; }
139
140 long PMAPI PM_getOSType(void)
141 { return _OS_SMX; }
142
143 int PMAPI PM_getModeType(void)
144 { return PM_386; }
145
146 void PMAPI PM_backslash(char *s)
147 {
148     uint pos = strlen(s);
149     if (s[pos-1] != '\\') {
150         s[pos] = '\\';
151         s[pos+1] = '\0';
152         }
153 }
154
155 void PMAPI PM_setFatalErrorCleanup(
156     void (PMAPIP cleanup)(void))
157 {
158     fatalErrorCleanup = cleanup;
159 }
160
161 void MGLOutput(char *);
162
163 void PMAPI PM_fatalError(const char *msg)
164 {
165     if (fatalErrorCleanup)
166         fatalErrorCleanup();
167     MGLOutput(msg);
168 // No support for fprintf() under smx currently!
169 //  fprintf(stderr,"%s\n", msg);
170     exit(1);
171 }
172
173 static void ExitVBEBuf(void)
174 {
175     if (VESABuf_ptr)
176         PM_freeRealSeg(VESABuf_ptr);
177     VESABuf_ptr = 0;
178 }
179
180 void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
181 {
182     if (!VESABuf_ptr) {
183         /* Allocate a global buffer for communicating with the VESA VBE */
184         if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL)
185             return NULL;
186         atexit(ExitVBEBuf);
187         }
188     *len = VESABuf_len;
189     *rseg = VESABuf_rseg;
190     *roff = VESABuf_roff;
191     return VESABuf_ptr;
192 }
193
194 int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out)
195 {
196     PMSREGS sregs;
197     PM_segread(&sregs);
198     return PM_int386x(intno,in,out,&sregs);
199 }
200
201 /* Routines to set and get the real mode interrupt vectors, by making
202  * direct real mode calls to DOS and bypassing the DOS extenders API.
203  * This is the safest way to handle this, as some servers try to be
204  * smart about changing real mode vectors.
205  */
206
207 void PMAPI _PM_getRMvect(int intno, long *realisr)
208 {
209     RMREGS  regs;
210     RMSREGS sregs;
211
212     PM_saveDS();
213     regs.h.ah = 0x35;
214     regs.h.al = intno;
215     PM_int86x(0x21, &regs, &regs, &sregs);
216     *realisr = ((long)sregs.es << 16) | regs.x.bx;
217 }
218
219 void PMAPI _PM_setRMvect(int intno, long realisr)
220 {
221     RMREGS  regs;
222     RMSREGS sregs;
223
224     PM_saveDS();
225     regs.h.ah = 0x25;
226     regs.h.al = intno;
227     sregs.ds = (int)(realisr >> 16);
228     regs.x.dx = (int)(realisr & 0xFFFF);
229     PM_int86x(0x21, &regs, &regs, &sregs);
230 }
231
232 void PMAPI _PM_addRealModeBlock(void *mem,uint tag)
233 {
234     int i;
235
236     for (i = 0; i < MAX_RM_BLOCKS; i++) {
237         if (rmBlocks[i].p == NULL) {
238             rmBlocks[i].p = mem;
239             rmBlocks[i].tag = tag;
240             return;
241             }
242         }
243     PM_fatalError("To many real mode memory block allocations!");
244 }
245
246 uint PMAPI _PM_findRealModeBlock(void *mem)
247 {
248     int i;
249
250     for (i = 0; i < MAX_RM_BLOCKS; i++) {
251         if (rmBlocks[i].p == mem)
252             return rmBlocks[i].tag;
253         }
254     PM_fatalError("Could not find prior real mode memory block allocation!");
255     return 0;
256 }
257
258 char * PMAPI PM_getCurrentPath(
259     char *path,
260     int maxLen)
261 {
262     return getcwd(path,maxLen);
263 }
264
265 char PMAPI PM_getBootDrive(void)
266 { return 'C'; }
267
268 const char * PMAPI PM_getVBEAFPath(void)
269 { return "c:\\"; }
270
271 const char * PMAPI PM_getNucleusPath(void)
272 {
273     static char path[256];
274     char        *env;
275
276     if ((env = getenv("NUCLEUS_PATH")) != NULL)
277         return env;
278     return "c:\\nucleus";
279 }
280
281 const char * PMAPI PM_getNucleusConfigPath(void)
282 {
283     static char path[256];
284     strcpy(path,PM_getNucleusPath());
285     PM_backslash(path);
286     strcat(path,"config");
287     return path;
288 }
289
290 const char * PMAPI PM_getUniqueID(void)
291 { return "SMX"; }
292
293 const char * PMAPI PM_getMachineName(void)
294 { return "SMX"; }
295
296 int PMAPI PM_kbhit(void)
297 {
298     int     hit;
299     event_t evt;
300
301     hit = EVT_peekNext(&evt,EVT_KEYDOWN | EVT_KEYREPEAT);
302     EVT_flush(~(EVT_KEYDOWN | EVT_KEYREPEAT));
303     return hit;
304 }
305
306 int PMAPI PM_getch(void)
307 {
308    event_t evt;
309
310     EVT_halt(&evt,EVT_KEYDOWN);
311    return EVT_asciiCode(evt.message);
312 }
313
314 PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen)
315 {
316     /* Not used for SMX */
317     (void)hwndUser;
318     (void)device;
319     (void)xRes;
320     (void)yRes;
321     (void)bpp;
322     (void)fullScreen;
323     return 0;
324 }
325
326 int PMAPI PM_getConsoleStateSize(void)
327 {
328     return sizeof(DOS_stateBuf);
329 }
330
331 void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole)
332 {
333     RMREGS          regs;
334     DOS_stateBuf    *sb = stateBuf;
335
336     /* Save the old video mode state */
337     regs.h.ah = 0x0F;
338     PM_int86(0x10,&regs,&regs);
339     sb->oldMode = regs.h.al & 0x7F;
340     sb->old50Lines = false;
341     if (sb->oldMode == 0x3) {
342         regs.x.ax = 0x1130;
343         regs.x.bx = 0;
344         regs.x.dx = 0;
345         PM_int86(0x10,&regs,&regs);
346         sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49);
347         }
348     (void)hwndConsole;
349 }
350
351 void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
352 {
353     /* Not used for SMX */
354     (void)saveState;
355 }
356
357 void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
358 {
359     RMREGS              regs;
360     const DOS_stateBuf  *sb = stateBuf;
361
362     /* Retore 50 line mode if set */
363     if (sb->old50Lines) {
364         regs.x.ax = 0x1112;
365         regs.x.bx = 0;
366         PM_int86(0x10,&regs,&regs);
367         }
368     (void)hwndConsole;
369 }
370
371 void PMAPI PM_closeConsole(PM_HWND hwndConsole)
372 {
373     /* Not used for SMX */
374     (void)hwndConsole;
375 }
376
377 void PMAPI PM_setOSCursorLocation(int x,int y)
378 {
379     uchar *_biosPtr = PM_getBIOSPointer();
380     PM_setByte(_biosPtr+0x50,x);
381     PM_setByte(_biosPtr+0x51,y);
382 }
383
384 void PMAPI PM_setOSScreenWidth(int width,int height)
385 {
386     uchar *_biosPtr = PM_getBIOSPointer();
387     PM_setWord(_biosPtr+0x4A,width);
388     PM_setWord(_biosPtr+0x4C,width*2);
389     PM_setByte(_biosPtr+0x84,height-1);
390     if (height > 25) {
391         PM_setWord(_biosPtr+0x60,0x0607);
392         PM_setByte(_biosPtr+0x85,0x08);
393         }
394     else {
395         PM_setWord(_biosPtr+0x60,0x0D0E);
396         PM_setByte(_biosPtr+0x85,0x016);
397         }
398 }
399
400 void * PMAPI PM_mallocShared(long size)
401 {
402     return PM_malloc(size);
403 }
404
405 void PMAPI PM_freeShared(void *ptr)
406 {
407     PM_free(ptr);
408 }
409
410 #define GetRMVect(intno,isr)    *(isr) = ((ulong*)rmZeroPtr)[intno]
411 #define SetRMVect(intno,isr)    ((ulong*)rmZeroPtr)[intno] = (isr)
412
413 ibool PMAPI PM_doBIOSPOST(
414     ushort axVal,
415     ulong BIOSPhysAddr,
416     void *mappedBIOS,
417     ulong BIOSLen)
418 {
419     static int      firstTime = true;
420     static uchar    *rmZeroPtr;
421     long            Current10,Current6D,Current42;
422     RMREGS          regs;
423     RMSREGS         sregs;
424
425     /* Create a zero memory mapping for us to use */
426     if (firstTime) {
427         rmZeroPtr = PM_mapPhysicalAddr(0,0x7FFF,true);
428         firstTime = false;
429         }
430
431     /* Remap the secondary BIOS to 0xC0000 physical */
432     if (BIOSPhysAddr != 0xC0000L || BIOSLen > 32768) {
433         /* SMX cannot virtually remap the BIOS, so we can only work if all
434          * the secondary controllers are identical, and we then use the
435          * BIOS on the first controller for all the remaining controllers.
436          *
437          * For OS'es that do virtual memory, and remapping of 0xC0000
438          * physical (perhaps a copy on write mapping) should be all that
439          * is needed.
440          */
441         return false;
442         }
443
444     /* Save current handlers of int 10h and 6Dh */
445     GetRMVect(0x10,&Current10);
446     GetRMVect(0x6D,&Current6D);
447
448     /* POST the secondary BIOS */
449     GetRMVect(0x42,&Current42);
450     SetRMVect(0x10,Current42);  /* Restore int 10h to STD-BIOS */
451     regs.x.ax = axVal;
452     PM_callRealMode(0xC000,0x0003,&regs,&sregs);
453
454     /* Restore current handlers */
455     SetRMVect(0x10,Current10);
456     SetRMVect(0x6D,Current6D);
457
458     /* Second the primary BIOS mappin 1:1 for 0xC0000 physical */
459     if (BIOSPhysAddr != 0xC0000L) {
460         /* SMX does not support this */
461         (void)mappedBIOS;
462         }
463     return true;
464 }
465
466 void PMAPI PM_sleep(ulong milliseconds)
467 {
468     ulong           microseconds = milliseconds * 1000L;
469     LZTimerObject   tm;
470
471     LZTimerOnExt(&tm);
472     while (LZTimerLapExt(&tm) < microseconds)
473         ;
474     LZTimerOffExt(&tm);
475 }
476
477 int PMAPI PM_getCOMPort(int port)
478 {
479     switch (port) {
480         case 0: return 0x3F8;
481         case 1: return 0x2F8;
482         }
483     return 0;
484 }
485
486 int PMAPI PM_getLPTPort(int port)
487 {
488     switch (port) {
489         case 0: return 0x3BC;
490         case 1: return 0x378;
491         case 2: return 0x278;
492         }
493     return 0;
494 }
495
496 PM_MODULE PMAPI PM_loadLibrary(
497     const char *szDLLName)
498 {
499     (void)szDLLName;
500     return NULL;
501 }
502
503 void * PMAPI PM_getProcAddress(
504     PM_MODULE hModule,
505     const char *szProcName)
506 {
507     (void)hModule;
508     (void)szProcName;
509     return NULL;
510 }
511
512 void PMAPI PM_freeLibrary(
513     PM_MODULE hModule)
514 {
515     (void)hModule;
516 }
517
518 int PMAPI PM_setIOPL(
519     int level)
520 {
521     return level;
522 }
523
524 /****************************************************************************
525 REMARKS:
526 Internal function to convert the find data to the generic interface.
527 ****************************************************************************/
528 static void convertFindData(
529     PM_findData *findData,
530     struct find_t *blk)
531 {
532     ulong   dwSize = findData->dwSize;
533
534     memset(findData,0,findData->dwSize);
535     findData->dwSize = dwSize;
536     if (blk->attrib & _A_RDONLY)
537         findData->attrib |= PM_FILE_READONLY;
538     if (blk->attrib & _A_SUBDIR)
539         findData->attrib |= PM_FILE_DIRECTORY;
540     if (blk->attrib & _A_ARCH)
541         findData->attrib |= PM_FILE_ARCHIVE;
542     if (blk->attrib & _A_HIDDEN)
543         findData->attrib |= PM_FILE_HIDDEN;
544     if (blk->attrib & _A_SYSTEM)
545         findData->attrib |= PM_FILE_SYSTEM;
546     findData->sizeLo = blk->size;
547     strncpy(findData->name,blk->name,PM_MAX_PATH);
548     findData->name[PM_MAX_PATH-1] = 0;
549 }
550
551 #define FIND_MASK   (_A_RDONLY | _A_ARCH | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM)
552
553 /****************************************************************************
554 REMARKS:
555 Function to find the first file matching a search criteria in a directory.
556 ****************************************************************************/
557 void * PMAPI PM_findFirstFile(
558     const char *filename,
559     PM_findData *findData)
560 {
561     struct find_t *blk;
562
563     if ((blk = PM_malloc(sizeof(*blk))) == NULL)
564         return PM_FILE_INVALID;
565     if (_dos_findfirst((char*)filename,FIND_MASK,blk) == 0) {
566         convertFindData(findData,blk);
567         return blk;
568         }
569     return PM_FILE_INVALID;
570 }
571
572 /****************************************************************************
573 REMARKS:
574 Function to find the next file matching a search criteria in a directory.
575 ****************************************************************************/
576 ibool PMAPI PM_findNextFile(
577     void *handle,
578     PM_findData *findData)
579 {
580     struct find_t *blk = handle;
581
582     if (_dos_findnext(blk) == 0) {
583         convertFindData(findData,blk);
584         return true;
585         }
586     return false;
587 }
588
589 /****************************************************************************
590 REMARKS:
591 Function to close the find process
592 ****************************************************************************/
593 void PMAPI PM_findClose(
594     void *handle)
595 {
596     PM_free(handle);
597 }
598
599 /****************************************************************************
600 REMARKS:
601 Function to determine if a drive is a valid drive or not. Under Unix this
602 function will return false for anything except a value of 3 (considered
603 the root drive, and equivalent to C: for non-Unix systems). The drive
604 numbering is:
605
606     1   - Drive A:
607     2   - Drive B:
608     3   - Drive C:
609     etc
610
611 ****************************************************************************/
612 ibool PMAPI PM_driveValid(
613     char drive)
614 {
615     RMREGS  regs;
616     regs.h.dl = (uchar)(drive - 'A' + 1);
617     regs.h.ah = 0x36;               // Get disk information service
618     PM_int86(0x21,&regs,&regs);
619     return regs.x.ax != 0xFFFF;     // AX = 0xFFFF if disk is invalid
620 }
621
622 /****************************************************************************
623 REMARKS:
624 Function to get the current working directory for the specififed drive.
625 Under Unix this will always return the current working directory regardless
626 of what the value of 'drive' is.
627 ****************************************************************************/
628 void PMAPI PM_getdcwd(
629     int drive,
630     char *dir,
631     int len)
632 {
633     uint oldDrive,maxDrives;
634     _dos_getdrive(&oldDrive);
635     _dos_setdrive(drive,&maxDrives);
636     getcwd(dir,len);
637     _dos_setdrive(oldDrive,&maxDrives);
638 }
639
640 /****************************************************************************
641 REMARKS:
642 Function to change the file attributes for a specific file.
643 ****************************************************************************/
644 void PMAPI PM_setFileAttr(
645     const char *filename,
646     uint attrib)
647 {
648 #if defined(TNT) && defined(_MSC_VER)
649     DWORD attr = 0;
650
651     if (attrib & PM_FILE_READONLY)
652         attr |= FILE_ATTRIBUTE_READONLY;
653     if (attrib & PM_FILE_ARCHIVE)
654         attr |= FILE_ATTRIBUTE_ARCHIVE;
655     if (attrib & PM_FILE_HIDDEN)
656         attr |= FILE_ATTRIBUTE_HIDDEN;
657     if (attrib & PM_FILE_SYSTEM)
658         attr |= FILE_ATTRIBUTE_SYSTEM;
659     SetFileAttributes((LPSTR)filename, attr);
660 #else
661     uint attr = 0;
662
663     if (attrib & PM_FILE_READONLY)
664         attr |= _A_RDONLY;
665     if (attrib & PM_FILE_ARCHIVE)
666         attr |= _A_ARCH;
667     if (attrib & PM_FILE_HIDDEN)
668         attr |= _A_HIDDEN;
669     if (attrib & PM_FILE_SYSTEM)
670         attr |= _A_SYSTEM;
671     _dos_setfileattr(filename,attr);
672 #endif
673 }
674
675 /****************************************************************************
676 REMARKS:
677 Function to create a directory.
678 ****************************************************************************/
679 ibool PMAPI PM_mkdir(
680     const char *filename)
681 {
682 #ifdef  __GNUC__
683     return mkdir(filename,S_IRUSR) == 0;
684 #else
685 //AM:   return mkdir(filename) == 0;
686     return(false);
687 #endif
688 }
689
690 /****************************************************************************
691 REMARKS:
692 Function to remove a directory.
693 ****************************************************************************/
694 ibool PMAPI PM_rmdir(
695     const char *filename)
696 {
697 //AM:   return rmdir(filename) == 0;
698     return(false);
699 }
700
701 /****************************************************************************
702 REMARKS:
703 Allocates a block of locked, physically contiguous memory. The memory
704 may be required to be below the 16Meg boundary.
705 ****************************************************************************/
706 void * PMAPI PM_allocLockedMem(
707     uint size,
708     ulong *physAddr,
709     ibool contiguous,
710     ibool below16M)
711 {
712     void            *p;
713     uint            r_seg,r_off;
714     PM_lockHandle   lh;
715
716     /* Under DOS the only way to know the physical memory address is to
717      * allocate the memory below the 1Meg boundary as real mode memory.
718      * We also allocate 4095 bytes more memory than we need, so we can
719      * properly page align the start of the memory block for DMA operations.
720      */
721     if (size > 4096)
722         return NULL;
723     if ((p = PM_allocRealSeg((size + 0xFFF) & ~0xFFF,&r_seg,&r_off)) == NULL)
724         return NULL;
725     *physAddr = ((r_seg << 4) + r_off + 0xFFF) & ~0xFFF;
726     PM_lockDataPages(p,size*2,&lh);
727     return p;
728 }
729
730 void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
731 {
732     (void)size;
733     PM_freeRealSeg(p);
734 }
735
736 /*-------------------------------------------------------------------------*/
737 /* Generic DPMI routines common to 16/32 bit code                          */
738 /*-------------------------------------------------------------------------*/
739
740 ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit)
741 {
742     PMREGS  r;
743     ulong   physOfs;
744
745     if (physAddr < 0x100000L) {
746         /* We can't map memory below 1Mb, but the linear address are already
747          * mapped 1:1 for this memory anyway so we just return the base address.
748          */
749         return physAddr;
750         }
751
752     /* Round the physical address to a 4Kb boundary and the limit to a
753      * 4Kb-1 boundary before passing the values to DPMI as some extenders
754      * will fail the calls unless this is the case. If we round the
755      * physical address, then we also add an extra offset into the address
756      * that we return.
757      */
758     physOfs = physAddr & 4095;
759     physAddr = physAddr & ~4095;
760     limit = ((limit+physOfs+1+4095) & ~4095)-1;
761
762     r.x.ax = 0x800;                 /* DPMI map physical to linear      */
763     r.x.bx = physAddr >> 16;
764     r.x.cx = physAddr & 0xFFFF;
765     r.x.si = limit >> 16;
766     r.x.di = limit & 0xFFFF;
767     PM_int386(0x31, &r, &r);
768     if (r.x.cflag)
769         return 0xFFFFFFFFUL;
770     return ((ulong)r.x.bx << 16) + r.x.cx + physOfs;
771 }
772
773 int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr)
774 {
775     PMREGS  r;
776
777     r.x.ax = 7;                     /* DPMI set selector base address   */
778     r.x.bx = sel;
779     r.x.cx = linAddr >> 16;
780     r.x.dx = linAddr & 0xFFFF;
781     PM_int386(0x31, &r, &r);
782     if (r.x.cflag)
783         return 0;
784     return 1;
785 }
786
787 ulong PMAPI DPMI_getSelectorBase(ushort sel)
788 {
789     PMREGS  r;
790
791     r.x.ax = 6;                     /* DPMI get selector base address   */
792     r.x.bx = sel;
793     PM_int386(0x31, &r, &r);
794     return ((ulong)r.x.cx << 16) + r.x.dx;
795 }
796
797 int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit)
798 {
799     PMREGS  r;
800
801     r.x.ax = 8;                     /* DPMI set selector limit          */
802     r.x.bx = sel;
803     r.x.cx = limit >> 16;
804     r.x.dx = limit & 0xFFFF;
805     PM_int386(0x31, &r, &r);
806     if (r.x.cflag)
807         return 0;
808     return 1;
809 }
810
811 uint PMAPI DPMI_createSelector(ulong base,ulong limit)
812 {
813     uint    sel;
814     PMREGS  r;
815
816     /* Allocate 1 descriptor */
817     r.x.ax = 0;
818     r.x.cx = 1;
819     PM_int386(0x31, &r, &r);
820     if (r.x.cflag) return 0;
821     sel = r.x.ax;
822
823     /* Set the descriptor access rights (for a 32 bit page granular
824      * segment, ring 0).
825      */
826     r.x.ax = 9;
827     r.x.bx = sel;
828     r.x.cx = 0x4093;
829     PM_int386(0x31, &r, &r);
830
831     /* Map physical memory and create selector */
832     if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL)
833         return 0;
834     if (!DPMI_setSelectorBase(sel,base))
835         return 0;
836     if (!DPMI_setSelectorLimit(sel,limit))
837         return 0;
838     return sel;
839 }
840
841 void PMAPI DPMI_freeSelector(uint sel)
842 {
843     PMREGS  r;
844
845     r.x.ax = 1;
846     r.x.bx = sel;
847     PM_int386(0x31, &r, &r);
848 }
849
850 int PMAPI DPMI_lockLinearPages(ulong linear,ulong len)
851 {
852     PMREGS  r;
853
854     r.x.ax = 0x600;                     /* DPMI Lock Linear Region      */
855     r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */
856     r.x.cx = (linear & 0xFFFF);
857     r.x.si = (len >> 16);               /* Length in SI:DI              */
858     r.x.di = (len & 0xFFFF);
859     PM_int386(0x31, &r, &r);
860     return (!r.x.cflag);
861 }
862
863 int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len)
864 {
865     PMREGS  r;
866
867     r.x.ax = 0x601;                     /* DPMI Unlock Linear Region    */
868     r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */
869     r.x.cx = (linear & 0xFFFF);
870     r.x.si = (len >> 16);               /* Length in SI:DI              */
871     r.x.di = (len & 0xFFFF);
872     PM_int386(0x31, &r, &r);
873     return (!r.x.cflag);
874 }
875
876 void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
877 {
878     PMSREGS sregs;
879     ulong   linAddr;
880     ulong   DSBaseAddr;
881
882     /* Get the base address for the default DS selector */
883     PM_segread(&sregs);
884     DSBaseAddr = DPMI_getSelectorBase(sregs.ds);
885     if ((base < 0x100000) && (DSBaseAddr == 0)) {
886         /* DS is zero based, so we can directly access the first 1Mb of
887          * system memory (like under DOS4GW).
888          */
889         return (void*)base;
890         }
891
892     /* Map the memory to a linear address using DPMI function 0x800 */
893     if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) {
894         if (base >= 0x100000)
895             return NULL;
896         /* If the linear address mapping fails but we are trying to
897          * map an area in the first 1Mb of system memory, then we must
898          * be running under a Windows or OS/2 DOS box. Under these
899          * environments we can use the segment wrap around as a fallback
900          * measure, as this does work properly.
901          */
902         linAddr = base;
903         }
904
905     /* Now expand the default DS selector to 4Gb so we can access it */
906     if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))
907         return NULL;
908
909     /* Finally enable caching for the page tables that we just mapped in,
910      * since DOS4GW and PMODE/W create the page table entries without
911      * caching enabled which hurts the performance of the linear framebuffer
912      * as it disables write combining on Pentium Pro and above processors.
913      *
914      * For those processors cache disabling is better handled through the
915      * MTRR registers anyway (we can write combine a region but disable
916      * caching) so that MMIO register regions do not screw up.
917      */
918     if (isCached) {
919         if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) {
920             int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
921             ulong   pageTable,*pPageTable;
922             if (!pPDB) {
923                 if (PDB >= 0x100000)
924                     pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
925                 else
926                     pPDB = (ulong*)PDB;
927                 }
928             if (pPDB) {
929                 startPDB = (linAddr >> 22) & 0x3FF;
930                 startPage = (linAddr >> 12) & 0x3FF;
931                 endPDB = ((linAddr+limit) >> 22) & 0x3FF;
932                 endPage = ((linAddr+limit) >> 12) & 0x3FF;
933                 for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
934                     pageTable = pPDB[iPDB] & ~0xFFF;
935                     if (pageTable >= 0x100000)
936                         pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
937                     else
938                         pPageTable = (ulong*)pageTable;
939                     start = (iPDB == startPDB) ? startPage : 0;
940                     end = (iPDB == endPDB) ? endPage : 0x3FF;
941                     for (iPage = start; iPage <= end; iPage++)
942                         pPageTable[iPage] &= ~0x18;
943                     }
944                 }
945             }
946         }
947
948     /* Now return the base address of the memory into the default DS */
949     return (void*)(linAddr - DSBaseAddr);
950 }
951
952 /* Some DOS extender implementations do not directly support calling a
953  * real mode procedure from protected mode. However we can simulate what
954  * we need temporarily hooking the INT 6Ah vector with a small real mode
955  * stub that will call our real mode code for us.
956  */
957
958 static uchar int6AHandler[] = {
959     0x00,0x00,0x00,0x00,        /*  __PMODE_callReal variable           */
960     0xFB,                       /*  sti                                 */
961     0x2E,0xFF,0x1E,0x00,0x00,   /*  call    [cs:__PMODE_callReal]       */
962     0xCF,                       /*  iretf                               */
963     };
964 static uchar *crPtr = NULL; /* Pointer to of int 6A handler         */
965 static uint crRSeg,crROff;  /* Real mode seg:offset of handler      */
966
967 void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
968     RMSREGS *sregs)
969 {
970     uchar   *p;
971     uint    oldSeg,oldOff;
972
973     if (!crPtr) {
974         /* Allocate and copy the memory block only once */
975         crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);
976         memcpy(crPtr,int6AHandler,sizeof(int6AHandler));
977         }
978     PM_setWord(crPtr,off);              /* Plug in address to call  */
979     PM_setWord(crPtr+2,seg);
980     p = PM_mapRealPointer(0,0x6A * 4);
981     oldOff = PM_getWord(p);             /* Save old handler address */
982     oldSeg = PM_getWord(p+2);
983     PM_setWord(p,crROff+4);             /* Hook 6A handler          */
984     PM_setWord(p+2,crRSeg);
985     PM_int86x(0x6A, in, in, sregs);     /* Call real mode code      */
986     PM_setWord(p,oldOff);               /* Restore old handler      */
987     PM_setWord(p+2,oldSeg);
988 }
989
990 void * PMAPI PM_getBIOSPointer(void)
991 { return PM_mapPhysicalAddr(0x400,0xFFFF,true); }
992
993 void * PMAPI PM_getA0000Pointer(void)
994 { return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
995
996 void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
997 { return DPMI_mapPhysicalAddr(base,limit,isCached); }
998
999 void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
1000 {
1001     /* Mapping cannot be free */
1002 }
1003
1004 ulong PMAPI PM_getPhysicalAddr(void *p)
1005 {
1006     // TODO: This function should find the physical address of a linear
1007     //       address.
1008     (void)p;
1009     return 0xFFFFFFFFUL;
1010 }
1011
1012 void * PMAPI PM_mapToProcess(void *base,ulong limit)
1013 {
1014     (void)limit;
1015     return (void*)base;
1016 }
1017
1018 void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
1019 {
1020     static uchar *zeroPtr = NULL;
1021
1022     if (!zeroPtr)
1023         zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
1024     return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
1025 }
1026
1027 void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
1028 {
1029     PMREGS      r;
1030     void        *p;
1031
1032     r.x.ax = 0x100;                 /* DPMI allocate DOS memory         */
1033     r.x.bx = (size + 0xF) >> 4;     /* number of paragraphs             */
1034     PM_int386(0x31, &r, &r);
1035     if (r.x.cflag)
1036         return NULL;                /* DPMI call failed                 */
1037     *r_seg = r.x.ax;                /* Real mode segment                */
1038     *r_off = 0;
1039     p = PM_mapRealPointer(*r_seg,*r_off);
1040     _PM_addRealModeBlock(p,r.x.dx);
1041     return p;
1042 }
1043
1044 void PMAPI PM_freeRealSeg(void *mem)
1045 {
1046     PMREGS  r;
1047
1048     r.x.ax = 0x101;                     /* DPMI free DOS memory         */
1049     r.x.dx = _PM_findRealModeBlock(mem);/* DX := selector from 0x100    */
1050     PM_int386(0x31, &r, &r);
1051 }
1052
1053 static DPMI_handler_t   DPMI_int10 = NULL;
1054
1055 void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler)
1056 {
1057     DPMI_int10 = handler;
1058 }
1059
1060 void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
1061 {
1062     PMREGS      r;
1063     PMSREGS     sr;
1064
1065     if (intno == 0x10 && DPMI_int10) {
1066         if (DPMI_int10(regs))
1067             return;
1068         }
1069     PM_segread(&sr);
1070     r.x.ax = 0x300;                 /* DPMI issue real interrupt    */
1071     r.h.bl = intno;
1072     r.h.bh = 0;
1073     r.x.cx = 0;
1074     sr.es = sr.ds;
1075     r.e.edi = (uint)regs;
1076     PM_int386x(0x31, &r, &r, &sr);  /* Issue the interrupt          */
1077 }
1078
1079 #define IN(reg)     rmregs.reg = in->e.reg
1080 #define OUT(reg)    out->e.reg = rmregs.reg
1081
1082 int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
1083 {
1084     DPMI_regs   rmregs;
1085
1086     memset(&rmregs, 0, sizeof(rmregs));
1087     IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1088
1089 // These real mode ints may cause crashes.
1090 //AM:   DPMI_int86(intno,&rmregs);      /* DPMI issue real interrupt    */
1091
1092     OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1093     out->x.cflag = rmregs.flags & 0x1;
1094     return out->x.ax;
1095 }
1096
1097 int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
1098     RMSREGS *sregs)
1099 {
1100     DPMI_regs   rmregs;
1101
1102     memset(&rmregs, 0, sizeof(rmregs));
1103     IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1104     rmregs.es = sregs->es;
1105     rmregs.ds = sregs->ds;
1106
1107 //AM:   DPMI_int86(intno,&rmregs);      /* DPMI issue real interrupt    */
1108
1109     OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1110     sregs->es = rmregs.es;
1111     sregs->cs = rmregs.cs;
1112     sregs->ss = rmregs.ss;
1113     sregs->ds = rmregs.ds;
1114     out->x.cflag = rmregs.flags & 0x1;
1115     return out->x.ax;
1116 }
1117
1118 #pragma pack(1)
1119
1120 typedef struct {
1121         uint    LargestBlockAvail;
1122         uint    MaxUnlockedPage;
1123         uint    LargestLockablePage;
1124         uint    LinAddrSpace;
1125         uint    NumFreePagesAvail;
1126         uint    NumPhysicalPagesFree;
1127         uint    TotalPhysicalPages;
1128         uint    FreeLinAddrSpace;
1129         uint    SizeOfPageFile;
1130         uint    res[3];
1131         } MemInfo;
1132
1133 #pragma pack()
1134
1135 void PMAPI PM_availableMemory(ulong *physical,ulong *total)
1136 {
1137     PMREGS  r;
1138     PMSREGS sr;
1139     MemInfo memInfo;
1140
1141     PM_segread(&sr);
1142     r.x.ax = 0x500;                 /* DPMI get free memory info */
1143     sr.es = sr.ds;
1144     r.e.edi = (uint)&memInfo;
1145     PM_int386x(0x31, &r, &r, &sr);  /* Issue the interrupt */
1146     *physical = memInfo.NumPhysicalPagesFree * 4096;
1147     *total = memInfo.LargestBlockAvail;
1148     if (*total < *physical)
1149         *physical = *total;
1150 }
1151
1152 /****************************************************************************
1153 REMARKS:
1154 Function to get the file attributes for a specific file.
1155 ****************************************************************************/
1156 uint PMAPI PM_getFileAttr(
1157     const char *filename)
1158 {
1159     // TODO: Implement this!
1160     return 0;
1161 }
1162
1163 /****************************************************************************
1164 REMARKS:
1165 Function to get the file time and date for a specific file.
1166 ****************************************************************************/
1167 ibool PMAPI PM_getFileTime(
1168     const char *filename,
1169     ibool gmTime,
1170     PM_time *time)
1171 {
1172     // TODO: Implement this!
1173     return false;
1174 }
1175
1176 /****************************************************************************
1177 REMARKS:
1178 Function to set the file time and date for a specific file.
1179 ****************************************************************************/
1180 ibool PMAPI PM_setFileTime(
1181     const char *filename,
1182     ibool gmTime,
1183     PM_time *time)
1184 {
1185     // TODO: Implement this!
1186     return false;
1187 }