]> git.ipfire.org Git - people/ms/u-boot.git/blob - 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
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 }