]> git.ipfire.org Git - people/ms/u-boot.git/blame - board/MAI/bios_emulator/scitech/src/pm/smx/pm.c
* Code cleanup:
[people/ms/u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / smx / pm.c
CommitLineData
c7de829c
WD
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
59typedef struct {
60 int oldMode;
61 int old50Lines;
62 } DOS_stateBuf;
63
64#define MAX_RM_BLOCKS 10
65
66static struct {
67 void *p;
68 uint tag;
69 } rmBlocks[MAX_RM_BLOCKS];
70
71static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */
72static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */
73static uint VESABuf_rseg; /* Real mode segment of VESABuf */
74static uint VESABuf_roff; /* Real mode offset of VESABuf */
75static void (PMAPIP fatalErrorCleanup)(void) = NULL;
76ushort _VARAPI _PM_savedDS = 0;
77static ulong PDB = 0,*pPDB = NULL;
78static uint VXD_version = -1;
79
80/*----------------------------- Implementation ----------------------------*/
81
82ulong _ASMAPI _PM_getPDB(void);
83void _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel);
84
85/****************************************************************************
86REMARKS:
87External function to call the PMHELP helper VxD.
88****************************************************************************/
89void PMAPI PM_VxDCall(
90 VXD_regs *regs)
91{
92}
93
94/****************************************************************************
95RETURNS:
96BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2)
97
98REMARKS:
99This function gets the version number for the VxD that we have connected to.
100****************************************************************************/
101uint PMAPI PMHELP_getVersion(void)
102{
103 return VXD_version = 0;
104}
105
106void PMAPI PM_init(void)
107{
108#ifndef REALMODE
109 MTRR_init();
110#endif
111}
112
113/****************************************************************************
114PARAMETERS:
115base - The starting physical base address of the region
116size - The size in bytes of the region
117type - Type to place into the MTRR register
118
119RETURNS:
120Error code describing the result.
121
122REMARKS:
123Function to enable write combining for the specified region of memory.
124****************************************************************************/
125int 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
137ibool PMAPI PM_haveBIOSAccess(void)
138{ return false; }
139
140long PMAPI PM_getOSType(void)
141{ return _OS_SMX; }
142
143int PMAPI PM_getModeType(void)
144{ return PM_386; }
145
146void PMAPI PM_backslash(char *s)
147{
148 uint pos = strlen(s);
149 if (s[pos-1] != '\\') {
8bde7f77
WD
150 s[pos] = '\\';
151 s[pos+1] = '\0';
152 }
c7de829c
WD
153}
154
155void PMAPI PM_setFatalErrorCleanup(
156 void (PMAPIP cleanup)(void))
157{
158 fatalErrorCleanup = cleanup;
159}
160
161void MGLOutput(char *);
162
163void PMAPI PM_fatalError(const char *msg)
164{
165 if (fatalErrorCleanup)
8bde7f77 166 fatalErrorCleanup();
c7de829c 167 MGLOutput(msg);
8bde7f77
WD
168/* No support for fprintf() under smx currently! */
169/* fprintf(stderr,"%s\n", msg); */
c7de829c
WD
170 exit(1);
171}
172
173static void ExitVBEBuf(void)
174{
175 if (VESABuf_ptr)
8bde7f77 176 PM_freeRealSeg(VESABuf_ptr);
c7de829c
WD
177 VESABuf_ptr = 0;
178}
179
180void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
181{
182 if (!VESABuf_ptr) {
8bde7f77
WD
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 }
c7de829c
WD
188 *len = VESABuf_len;
189 *rseg = VESABuf_rseg;
190 *roff = VESABuf_roff;
191 return VESABuf_ptr;
192}
193
194int 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
207void 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
219void 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
232void PMAPI _PM_addRealModeBlock(void *mem,uint tag)
233{
234 int i;
235
236 for (i = 0; i < MAX_RM_BLOCKS; i++) {
8bde7f77
WD
237 if (rmBlocks[i].p == NULL) {
238 rmBlocks[i].p = mem;
239 rmBlocks[i].tag = tag;
240 return;
241 }
242 }
c7de829c
WD
243 PM_fatalError("To many real mode memory block allocations!");
244}
245
246uint PMAPI _PM_findRealModeBlock(void *mem)
247{
248 int i;
249
250 for (i = 0; i < MAX_RM_BLOCKS; i++) {
8bde7f77
WD
251 if (rmBlocks[i].p == mem)
252 return rmBlocks[i].tag;
253 }
c7de829c
WD
254 PM_fatalError("Could not find prior real mode memory block allocation!");
255 return 0;
256}
257
258char * PMAPI PM_getCurrentPath(
259 char *path,
260 int maxLen)
261{
262 return getcwd(path,maxLen);
263}
264
265char PMAPI PM_getBootDrive(void)
266{ return 'C'; }
267
268const char * PMAPI PM_getVBEAFPath(void)
269{ return "c:\\"; }
270
271const char * PMAPI PM_getNucleusPath(void)
272{
273 static char path[256];
274 char *env;
275
276 if ((env = getenv("NUCLEUS_PATH")) != NULL)
8bde7f77 277 return env;
c7de829c
WD
278 return "c:\\nucleus";
279}
280
281const 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
290const char * PMAPI PM_getUniqueID(void)
291{ return "SMX"; }
292
293const char * PMAPI PM_getMachineName(void)
294{ return "SMX"; }
295
296int 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
306int PMAPI PM_getch(void)
307{
308 event_t evt;
309
310 EVT_halt(&evt,EVT_KEYDOWN);
311 return EVT_asciiCode(evt.message);
312}
313
314PM_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
326int PMAPI PM_getConsoleStateSize(void)
327{
328 return sizeof(DOS_stateBuf);
329}
330
331void 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) {
8bde7f77
WD
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 }
c7de829c
WD
348 (void)hwndConsole;
349}
350
351void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
352{
353 /* Not used for SMX */
354 (void)saveState;
355}
356
357void 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) {
8bde7f77
WD
364 regs.x.ax = 0x1112;
365 regs.x.bx = 0;
366 PM_int86(0x10,&regs,&regs);
367 }
c7de829c
WD
368 (void)hwndConsole;
369}
370
371void PMAPI PM_closeConsole(PM_HWND hwndConsole)
372{
373 /* Not used for SMX */
374 (void)hwndConsole;
375}
376
377void 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
384void 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) {
8bde7f77
WD
391 PM_setWord(_biosPtr+0x60,0x0607);
392 PM_setByte(_biosPtr+0x85,0x08);
393 }
c7de829c 394 else {
8bde7f77
WD
395 PM_setWord(_biosPtr+0x60,0x0D0E);
396 PM_setByte(_biosPtr+0x85,0x016);
397 }
c7de829c
WD
398}
399
400void * PMAPI PM_mallocShared(long size)
401{
402 return PM_malloc(size);
403}
404
405void 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
413ibool 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) {
8bde7f77
WD
427 rmZeroPtr = PM_mapPhysicalAddr(0,0x7FFF,true);
428 firstTime = false;
429 }
c7de829c
WD
430
431 /* Remap the secondary BIOS to 0xC0000 physical */
432 if (BIOSPhysAddr != 0xC0000L || BIOSLen > 32768) {
8bde7f77
WD
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 }
c7de829c
WD
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) {
8bde7f77
WD
460 /* SMX does not support this */
461 (void)mappedBIOS;
462 }
c7de829c
WD
463 return true;
464}
465
466void PMAPI PM_sleep(ulong milliseconds)
467{
468 ulong microseconds = milliseconds * 1000L;
469 LZTimerObject tm;
470
471 LZTimerOnExt(&tm);
472 while (LZTimerLapExt(&tm) < microseconds)
8bde7f77 473 ;
c7de829c
WD
474 LZTimerOffExt(&tm);
475}
476
477int PMAPI PM_getCOMPort(int port)
478{
479 switch (port) {
8bde7f77
WD
480 case 0: return 0x3F8;
481 case 1: return 0x2F8;
482 }
c7de829c
WD
483 return 0;
484}
485
486int PMAPI PM_getLPTPort(int port)
487{
488 switch (port) {
8bde7f77
WD
489 case 0: return 0x3BC;
490 case 1: return 0x378;
491 case 2: return 0x278;
492 }
c7de829c
WD
493 return 0;
494}
495
496PM_MODULE PMAPI PM_loadLibrary(
497 const char *szDLLName)
498{
499 (void)szDLLName;
500 return NULL;
501}
502
503void * PMAPI PM_getProcAddress(
504 PM_MODULE hModule,
505 const char *szProcName)
506{
507 (void)hModule;
508 (void)szProcName;
509 return NULL;
510}
511
512void PMAPI PM_freeLibrary(
513 PM_MODULE hModule)
514{
515 (void)hModule;
516}
517
518int PMAPI PM_setIOPL(
519 int level)
520{
521 return level;
522}
523
524/****************************************************************************
525REMARKS:
526Internal function to convert the find data to the generic interface.
527****************************************************************************/
528static 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)
8bde7f77 537 findData->attrib |= PM_FILE_READONLY;
c7de829c 538 if (blk->attrib & _A_SUBDIR)
8bde7f77 539 findData->attrib |= PM_FILE_DIRECTORY;
c7de829c 540 if (blk->attrib & _A_ARCH)
8bde7f77 541 findData->attrib |= PM_FILE_ARCHIVE;
c7de829c 542 if (blk->attrib & _A_HIDDEN)
8bde7f77 543 findData->attrib |= PM_FILE_HIDDEN;
c7de829c 544 if (blk->attrib & _A_SYSTEM)
8bde7f77 545 findData->attrib |= PM_FILE_SYSTEM;
c7de829c
WD
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/****************************************************************************
554REMARKS:
555Function to find the first file matching a search criteria in a directory.
556****************************************************************************/
557void * 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)
8bde7f77 564 return PM_FILE_INVALID;
c7de829c 565 if (_dos_findfirst((char*)filename,FIND_MASK,blk) == 0) {
8bde7f77
WD
566 convertFindData(findData,blk);
567 return blk;
568 }
c7de829c
WD
569 return PM_FILE_INVALID;
570}
571
572/****************************************************************************
573REMARKS:
574Function to find the next file matching a search criteria in a directory.
575****************************************************************************/
576ibool PMAPI PM_findNextFile(
577 void *handle,
578 PM_findData *findData)
579{
580 struct find_t *blk = handle;
581
582 if (_dos_findnext(blk) == 0) {
8bde7f77
WD
583 convertFindData(findData,blk);
584 return true;
585 }
c7de829c
WD
586 return false;
587}
588
589/****************************************************************************
590REMARKS:
591Function to close the find process
592****************************************************************************/
593void PMAPI PM_findClose(
594 void *handle)
595{
596 PM_free(handle);
597}
598
599/****************************************************************************
600REMARKS:
601Function to determine if a drive is a valid drive or not. Under Unix this
602function will return false for anything except a value of 3 (considered
603the root drive, and equivalent to C: for non-Unix systems). The drive
604numbering is:
605
606 1 - Drive A:
607 2 - Drive B:
608 3 - Drive C:
609 etc
610
611****************************************************************************/
612ibool PMAPI PM_driveValid(
613 char drive)
614{
615 RMREGS regs;
616 regs.h.dl = (uchar)(drive - 'A' + 1);
8bde7f77 617 regs.h.ah = 0x36; /* Get disk information service */
c7de829c 618 PM_int86(0x21,&regs,&regs);
8bde7f77 619 return regs.x.ax != 0xFFFF; /* AX = 0xFFFF if disk is invalid */
c7de829c
WD
620}
621
622/****************************************************************************
623REMARKS:
624Function to get the current working directory for the specififed drive.
625Under Unix this will always return the current working directory regardless
626of what the value of 'drive' is.
627****************************************************************************/
628void 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/****************************************************************************
641REMARKS:
642Function to change the file attributes for a specific file.
643****************************************************************************/
644void 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)
8bde7f77 652 attr |= FILE_ATTRIBUTE_READONLY;
c7de829c 653 if (attrib & PM_FILE_ARCHIVE)
8bde7f77 654 attr |= FILE_ATTRIBUTE_ARCHIVE;
c7de829c 655 if (attrib & PM_FILE_HIDDEN)
8bde7f77 656 attr |= FILE_ATTRIBUTE_HIDDEN;
c7de829c 657 if (attrib & PM_FILE_SYSTEM)
8bde7f77 658 attr |= FILE_ATTRIBUTE_SYSTEM;
c7de829c
WD
659 SetFileAttributes((LPSTR)filename, attr);
660#else
661 uint attr = 0;
662
663 if (attrib & PM_FILE_READONLY)
8bde7f77 664 attr |= _A_RDONLY;
c7de829c 665 if (attrib & PM_FILE_ARCHIVE)
8bde7f77 666 attr |= _A_ARCH;
c7de829c 667 if (attrib & PM_FILE_HIDDEN)
8bde7f77 668 attr |= _A_HIDDEN;
c7de829c 669 if (attrib & PM_FILE_SYSTEM)
8bde7f77 670 attr |= _A_SYSTEM;
c7de829c
WD
671 _dos_setfileattr(filename,attr);
672#endif
673}
674
675/****************************************************************************
676REMARKS:
677Function to create a directory.
678****************************************************************************/
679ibool PMAPI PM_mkdir(
680 const char *filename)
681{
682#ifdef __GNUC__
683 return mkdir(filename,S_IRUSR) == 0;
684#else
8bde7f77 685/*AM: return mkdir(filename) == 0; */
c7de829c
WD
686 return(false);
687#endif
688}
689
690/****************************************************************************
691REMARKS:
692Function to remove a directory.
693****************************************************************************/
694ibool PMAPI PM_rmdir(
695 const char *filename)
696{
8bde7f77 697/*AM: return rmdir(filename) == 0; */
c7de829c
WD
698 return(false);
699}
700
701/****************************************************************************
702REMARKS:
703Allocates a block of locked, physically contiguous memory. The memory
704may be required to be below the 16Meg boundary.
705****************************************************************************/
706void * 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)
8bde7f77 722 return NULL;
c7de829c 723 if ((p = PM_allocRealSeg((size + 0xFFF) & ~0xFFF,&r_seg,&r_off)) == NULL)
8bde7f77 724 return NULL;
c7de829c
WD
725 *physAddr = ((r_seg << 4) + r_off + 0xFFF) & ~0xFFF;
726 PM_lockDataPages(p,size*2,&lh);
727 return p;
728}
729
730void 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
740ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit)
741{
742 PMREGS r;
743 ulong physOfs;
744
745 if (physAddr < 0x100000L) {
8bde7f77
WD
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 }
c7de829c
WD
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)
8bde7f77 769 return 0xFFFFFFFFUL;
c7de829c
WD
770 return ((ulong)r.x.bx << 16) + r.x.cx + physOfs;
771}
772
773int 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)
8bde7f77 783 return 0;
c7de829c
WD
784 return 1;
785}
786
787ulong 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
797int 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)
8bde7f77 807 return 0;
c7de829c
WD
808 return 1;
809}
810
811uint 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)
8bde7f77 833 return 0;
c7de829c 834 if (!DPMI_setSelectorBase(sel,base))
8bde7f77 835 return 0;
c7de829c 836 if (!DPMI_setSelectorLimit(sel,limit))
8bde7f77 837 return 0;
c7de829c
WD
838 return sel;
839}
840
841void 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
850int 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
863int 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
876void * 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)) {
8bde7f77
WD
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 }
c7de829c
WD
891
892 /* Map the memory to a linear address using DPMI function 0x800 */
893 if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) {
8bde7f77
WD
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 }
c7de829c
WD
904
905 /* Now expand the default DS selector to 4Gb so we can access it */
906 if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))
8bde7f77 907 return NULL;
c7de829c
WD
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) {
8bde7f77
WD
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 }
c7de829c
WD
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
958static 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 };
964static uchar *crPtr = NULL; /* Pointer to of int 6A handler */
965static uint crRSeg,crROff; /* Real mode seg:offset of handler */
966
967void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
968 RMSREGS *sregs)
969{
970 uchar *p;
971 uint oldSeg,oldOff;
972
973 if (!crPtr) {
8bde7f77
WD
974 /* Allocate and copy the memory block only once */
975 crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);
976 memcpy(crPtr,int6AHandler,sizeof(int6AHandler));
977 }
c7de829c
WD
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
990void * PMAPI PM_getBIOSPointer(void)
991{ return PM_mapPhysicalAddr(0x400,0xFFFF,true); }
992
993void * PMAPI PM_getA0000Pointer(void)
994{ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
995
996void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
997{ return DPMI_mapPhysicalAddr(base,limit,isCached); }
998
999void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
1000{
1001 /* Mapping cannot be free */
1002}
1003
1004ulong PMAPI PM_getPhysicalAddr(void *p)
1005{
8bde7f77
WD
1006 /* TODO: This function should find the physical address of a linear */
1007 /* address. */
c7de829c
WD
1008 (void)p;
1009 return 0xFFFFFFFFUL;
1010}
1011
1012void * PMAPI PM_mapToProcess(void *base,ulong limit)
1013{
1014 (void)limit;
1015 return (void*)base;
1016}
1017
1018void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
1019{
1020 static uchar *zeroPtr = NULL;
1021
1022 if (!zeroPtr)
8bde7f77 1023 zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
c7de829c
WD
1024 return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
1025}
1026
1027void * 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)
8bde7f77 1036 return NULL; /* DPMI call failed */
c7de829c
WD
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
1044void 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
1053static DPMI_handler_t DPMI_int10 = NULL;
1054
1055void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler)
1056{
1057 DPMI_int10 = handler;
1058}
1059
1060void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
1061{
1062 PMREGS r;
1063 PMSREGS sr;
1064
1065 if (intno == 0x10 && DPMI_int10) {
8bde7f77
WD
1066 if (DPMI_int10(regs))
1067 return;
1068 }
c7de829c
WD
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
1082int 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
8bde7f77
WD
1089/* These real mode ints may cause crashes. */
1090/*AM: DPMI_int86(intno,&rmregs); /###* DPMI issue real interrupt */
c7de829c
WD
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
1097int 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
8bde7f77 1107/*AM: DPMI_int86(intno,&rmregs); /###* DPMI issue real interrupt */
c7de829c
WD
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
1120typedef struct {
8bde7f77
WD
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;
c7de829c
WD
1132
1133#pragma pack()
1134
1135void 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)
8bde7f77 1149 *physical = *total;
c7de829c
WD
1150}
1151
1152/****************************************************************************
1153REMARKS:
1154Function to get the file attributes for a specific file.
1155****************************************************************************/
1156uint PMAPI PM_getFileAttr(
1157 const char *filename)
1158{
8bde7f77 1159 /* TODO: Implement this! */
c7de829c
WD
1160 return 0;
1161}
1162
1163/****************************************************************************
1164REMARKS:
1165Function to get the file time and date for a specific file.
1166****************************************************************************/
1167ibool PMAPI PM_getFileTime(
1168 const char *filename,
1169 ibool gmTime,
1170 PM_time *time)
1171{
8bde7f77 1172 /* TODO: Implement this! */
c7de829c
WD
1173 return false;
1174}
1175
1176/****************************************************************************
1177REMARKS:
1178Function to set the file time and date for a specific file.
1179****************************************************************************/
1180ibool PMAPI PM_setFileTime(
1181 const char *filename,
1182 ibool gmTime,
1183 PM_time *time)
1184{
8bde7f77 1185 /* TODO: Implement this! */
c7de829c
WD
1186 return false;
1187}