]>
Commit | Line | Data |
---|---|---|
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 | ||
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] != '\\') { | |
8bde7f77 WD |
150 | s[pos] = '\\'; |
151 | s[pos+1] = '\0'; | |
152 | } | |
c7de829c WD |
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) | |
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 | ||
173 | static void ExitVBEBuf(void) | |
174 | { | |
175 | if (VESABuf_ptr) | |
8bde7f77 | 176 | PM_freeRealSeg(VESABuf_ptr); |
c7de829c WD |
177 | VESABuf_ptr = 0; |
178 | } | |
179 | ||
180 | void * 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 | ||
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, ®s, ®s, &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, ®s, ®s, &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++) { | |
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 | ||
246 | uint 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 | ||
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) | |
8bde7f77 | 277 | return env; |
c7de829c WD |
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,®s,®s); | |
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,®s,®s); | |
346 | sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49); | |
347 | } | |
c7de829c WD |
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) { | |
8bde7f77 WD |
364 | regs.x.ax = 0x1112; |
365 | regs.x.bx = 0; | |
366 | PM_int86(0x10,®s,®s); | |
367 | } | |
c7de829c WD |
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) { | |
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 | ||
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) { | |
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,®s,&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 | ||
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) | |
8bde7f77 | 473 | ; |
c7de829c WD |
474 | LZTimerOffExt(&tm); |
475 | } | |
476 | ||
477 | int 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 | ||
486 | int 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 | ||
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) | |
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 | /**************************************************************************** | |
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) | |
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 | /**************************************************************************** | |
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) { | |
8bde7f77 WD |
583 | convertFindData(findData,blk); |
584 | return true; | |
585 | } | |
c7de829c WD |
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); | |
8bde7f77 | 617 | regs.h.ah = 0x36; /* Get disk information service */ |
c7de829c | 618 | PM_int86(0x21,®s,®s); |
8bde7f77 | 619 | return regs.x.ax != 0xFFFF; /* AX = 0xFFFF if disk is invalid */ |
c7de829c WD |
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) | |
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 | /**************************************************************************** | |
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 | |
8bde7f77 | 685 | /*AM: return mkdir(filename) == 0; */ |
c7de829c WD |
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 | { | |
8bde7f77 | 697 | /*AM: return rmdir(filename) == 0; */ |
c7de829c WD |
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) | |
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 | ||
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) { | |
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 | ||
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) | |
8bde7f77 | 783 | return 0; |
c7de829c WD |
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) | |
8bde7f77 | 807 | return 0; |
c7de829c WD |
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) | |
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 | ||
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)) { | |
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 | ||
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) { | |
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 | ||
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 | { | |
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 | ||
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) | |
8bde7f77 | 1023 | zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true); |
c7de829c WD |
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) | |
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 | ||
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) { | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
1120 | typedef 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 | ||
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) | |
8bde7f77 | 1149 | *physical = *total; |
c7de829c WD |
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 | { | |
8bde7f77 | 1159 | /* TODO: Implement this! */ |
c7de829c WD |
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 | { | |
8bde7f77 | 1172 | /* TODO: Implement this! */ |
c7de829c WD |
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 | { | |
8bde7f77 | 1185 | /* TODO: Implement this! */ |
c7de829c WD |
1186 | return false; |
1187 | } |