ReactOS 0.4.15-dev-7961-gdcf9eb0
dos.c File Reference
#include "ntvdm.h"
#include <debug.h>
#include "emulator.h"
#include "cpu/cpu.h"
#include "int32.h"
#include "dos.h"
#include "dos/dem.h"
#include "country.h"
#include "device.h"
#include "handle.h"
#include "dosfiles.h"
#include "memory.h"
#include "process.h"
#include "himem.h"
#include "bios/bios.h"
#include "io.h"
#include "hardware/ps2.h"
#include "emsdrv.h"
Include dependency graph for dos.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

static BOOLEAN DosChangeDrive (BYTE Drive)
 
static BOOLEAN DosChangeDirectory (LPSTR Directory)
 
static BOOLEAN DosIsFileOnCdRom (VOID)
 
BOOLEAN DosControlBreak (VOID)
 
VOID WINAPI DosInt20h (LPWORD Stack)
 
VOID WINAPI DosInt21h (LPWORD Stack)
 
VOID WINAPI DosBreakInterrupt (LPWORD Stack)
 
VOID WINAPI DosAbsoluteRead (LPWORD Stack)
 
VOID WINAPI DosAbsoluteWrite (LPWORD Stack)
 
VOID WINAPI DosInt27h (LPWORD Stack)
 
VOID WINAPI DosIdle (LPWORD Stack)
 
VOID WINAPI DosFastConOut (LPWORD Stack)
 
VOID WINAPI DosInt2Ah (LPWORD Stack)
 
VOID WINAPI DosInt2Fh (LPWORD Stack)
 
BOOLEAN DosKRNLInitialize (VOID)
 

Variables

CALLBACK16 DosContext
 
PDOS_DATA DosData
 
PDOS_SYSVARS SysVars
 
PDOS_SDA Sda
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file dos.c.

Function Documentation

◆ DosAbsoluteRead()

VOID WINAPI DosAbsoluteRead ( LPWORD  Stack)

Definition at line 2032 of file dos.c.

2033{
2034 /*
2035 * This call should leave the flags on the stack for some reason,
2036 * so move the stack by one word.
2037 * See: http://www.techhelpmanual.com/565-int_25h_26h__absolute_disk_read_write.html
2038 */
2042 setSP(LOWORD(getSP() - 2));
2043
2044 // TODO: NOT IMPLEMENTED;
2046
2047 /* General failure */
2048 setAX(0x800C);
2050}
#define UNIMPLEMENTED
Definition: debug.h:115
#define STACK_IP
Definition: int32.h:33
#define STACK_FLAGS
Definition: int32.h:35
#define STACK_INT_NUM
Definition: int32.h:30
#define STACK_CS
Definition: int32.h:34
#define LOWORD(l)
Definition: pedump.c:82
#define EMULATOR_FLAG_CF
Definition: cpu.h:19
VOID WINAPI setSP(USHORT)
Definition: registers.c:351
USHORT WINAPI getSP(VOID)
Definition: registers.c:344
VOID WINAPI setAX(USHORT)
Definition: registers.c:121
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639

Referenced by DosKRNLInitialize().

◆ DosAbsoluteWrite()

VOID WINAPI DosAbsoluteWrite ( LPWORD  Stack)

Definition at line 2052 of file dos.c.

2053{
2054 /*
2055 * This call should leave the flags on the stack for some reason,
2056 * so move the stack by one word.
2057 * See: http://www.techhelpmanual.com/565-int_25h_26h__absolute_disk_read_write.html
2058 */
2062 setSP(LOWORD(getSP() - 2));
2063
2064 // TODO: NOT IMPLEMENTED;
2066
2067 /* General failure */
2068 setAX(0x800C);
2070}

Referenced by DosKRNLInitialize().

◆ DosBreakInterrupt()

VOID WINAPI DosBreakInterrupt ( LPWORD  Stack)

Definition at line 2026 of file dos.c.

2027{
2028 /* Set CF to terminate the running process */
2030}

Referenced by DosKRNLInitialize().

◆ DosChangeDirectory()

static BOOLEAN DosChangeDirectory ( LPSTR  Directory)
static

Definition at line 78 of file dos.c.

79{
80 BYTE DriveNumber;
82 LPSTR Path;
84 CHAR DosDirectory[DOS_DIR_LENGTH];
85
86 /* Make sure the directory path is not too long */
88 {
90 return FALSE;
91 }
92
93 /* Check whether the directory string is of format "X:..." */
94 if (strlen(Directory) >= 2 && Directory[1] == ':')
95 {
96 /* Get the drive number */
97 DriveNumber = RtlUpperChar(Directory[0]) - 'A';
98
99 /* Make sure the drive exists */
100 if (DriveNumber >= SysVars->NumLocalDrives)
101 {
103 return FALSE;
104 }
105 }
106 else
107 {
108 /* Keep the current drive number */
109 DriveNumber = Sda->CurrentDrive;
110 }
111
112 /* Get the file attributes */
114
115 /* Make sure the path exists and is a directory */
118 {
120 return FALSE;
121 }
122
123 /* Check if this is the current drive */
124 if (DriveNumber == Sda->CurrentDrive)
125 {
126 /* Change the directory */
128 {
130 return FALSE;
131 }
132 }
133
134 /* Get the (possibly new) current directory (needed if we specified a relative directory) */
136 {
137 // TODO: Use some kind of default path?
138 return FALSE;
139 }
140
141 /* Convert it to a DOS path */
142 if (!GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory)))
143 {
144 // TODO: Use some kind of default path?
145 return FALSE;
146 }
147
148 /* Get the directory part of the path and set the current directory for the drive */
149 Path = strchr(DosDirectory, '\\');
150 if (Path != NULL)
151 {
152 Path++; // Skip the backslash
154 }
155 else
156 {
157 DosData->CurrentDirectories[DriveNumber][0] = '\0';
158 }
159
160 /* Return success */
161 return TRUE;
162}
PRTL_UNICODE_STRING_BUFFER Path
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
char * strchr(const char *String, int ch)
Definition: utclib.c:501
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c:74
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define MAX_PATH
Definition: compat.h:34
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:636
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2146
DWORD WINAPI GetShortPathNameA(IN LPCSTR lpszLongPath, OUT LPSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1752
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2206
PDOS_SYSVARS SysVars
Definition: dos.c:47
PDOS_SDA Sda
Definition: dos.c:48
PDOS_DATA DosData
Definition: dos.c:45
unsigned long DWORD
Definition: ntddk_ex.h:95
CHAR NTAPI RtlUpperChar(_In_ CHAR Source)
Definition: nlsboot.c:229
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
base for all directory entries
Definition: entries.h:138
CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]
Definition: dos.h:257
WORD LastErrorCode
Definition: dos.h:160
BYTE CurrentDrive
Definition: dos.h:168
BYTE NumLocalDrives
Definition: dos.h:88
#define DOS_DIR_LENGTH
Definition: dos.h:47
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
char * LPSTR
Definition: xmlstorage.h:182
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193

Referenced by DosInt21h().

◆ DosChangeDrive()

static BOOLEAN DosChangeDrive ( BYTE  Drive)
static

Definition at line 52 of file dos.c.

53{
54 CHAR DirectoryPath[DOS_CMDLINE_LENGTH + 1];
55
56 /* Make sure the drive exists */
57 if (Drive >= SysVars->NumLocalDrives) return FALSE;
58
59 RtlZeroMemory(DirectoryPath, sizeof(DirectoryPath));
60
61 /* Find the path to the new current directory */
62 snprintf(DirectoryPath,
64 "%c:\\%s",
65 'A' + Drive,
67
68 /* Change the current directory of the process */
69 if (!SetCurrentDirectoryA(DirectoryPath)) return FALSE;
70
71 /* Set the current drive */
73
74 /* Return success */
75 return TRUE;
76}
PWCHAR Drive
Definition: chkdsk.c:73
#define DOS_CMDLINE_LENGTH
Definition: process.h:13
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define snprintf
Definition: wintirpc.h:48

Referenced by DosInt21h().

◆ DosControlBreak()

BOOLEAN DosControlBreak ( VOID  )

Definition at line 181 of file dos.c.

182{
183 setCF(0);
184
185 /* Print an extra newline */
188
189 /* Call interrupt 0x23 */
190 Int32Call(&DosContext, 0x23);
191
192 if (getCF())
193 {
195 return TRUE;
196 }
197
198 return FALSE;
199}
CALLBACK16 DosContext
Definition: dos.c:40
VOID Int32Call(IN PCALLBACK16 Context, IN BYTE IntNumber)
Definition: int32.c:151
WORD CurrentPsp
Definition: dos.h:165
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
Definition: bios.c:152
#define DOS_OUTPUT_HANDLE
Definition: dos.h:43
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
Definition: process.c:936
ULONG WINAPI getCF(VOID)
Definition: registers.c:566
VOID WINAPI setCF(ULONG)
Definition: registers.c:573

Referenced by DosInt21h(), and DosReadLineBuffered().

◆ DosFastConOut()

VOID WINAPI DosFastConOut ( LPWORD  Stack)

Definition at line 2090 of file dos.c.

2091{
2092 /*
2093 * This is the DOS 2+ Fast Console Output Interrupt.
2094 * The default handler under DOS 2.x and 3.x simply calls INT 10h/AH=0Eh.
2095 *
2096 * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
2097 * for more information.
2098 */
2099
2100 /* Save AX and BX */
2101 USHORT AX = getAX();
2102 USHORT BX = getBX();
2103
2104 /*
2105 * Set the parameters:
2106 * AL contains the character to print (already set),
2107 * BL contains the character attribute,
2108 * BH contains the video page to use.
2109 */
2112
2113 /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
2114 setAH(0x0E);
2116
2117 /* Restore AX and BX */
2118 setBX(BX);
2119 setAX(AX);
2120}
#define AX
Definition: i386-dis.c:424
unsigned short USHORT
Definition: pedump.c:61
BYTE VideoPage
Definition: bios.h:66
PBIOS_DATA_AREA Bda
Definition: bios.c:42
#define DOS_CHAR_ATTRIBUTE
Definition: dos.h:49
VOID WINAPI setBX(USHORT)
Definition: registers.c:177
USHORT WINAPI getBX(VOID)
Definition: registers.c:170
VOID WINAPI setAH(UCHAR)
Definition: registers.c:135
VOID WINAPI setBL(UCHAR)
Definition: registers.c:205
USHORT WINAPI getAX(VOID)
Definition: registers.c:114
VOID WINAPI setBH(UCHAR)
Definition: registers.c:191
#define BIOS_VIDEO_INTERRUPT
Definition: vidbios.h:15

Referenced by DosKRNLInitialize().

◆ DosIdle()

VOID WINAPI DosIdle ( LPWORD  Stack)

Definition at line 2081 of file dos.c.

2082{
2083 /*
2084 * This will set the carry flag on the first call (to repeat the BOP),
2085 * and clear it in the next, so that exactly one HLT occurs.
2086 */
2087 setCF(!getCF());
2088}

Referenced by DosKRNLInitialize().

◆ DosInt20h()

VOID WINAPI DosInt20h ( LPWORD  Stack)

Definition at line 201 of file dos.c.

202{
203 /*
204 * This is the exit interrupt (alias to INT 21h, AH=00h).
205 * CS must be the PSP segment.
206 */
208}

Referenced by DosKRNLInitialize().

◆ DosInt21h()

VOID WINAPI DosInt21h ( LPWORD  Stack)

Definition at line 210 of file dos.c.

211{
212 BYTE Character;
213 SYSTEMTIME SystemTime;
215
216 Sda->InDos++;
217
218 /* Save the value of SS:SP on entry in the PSP */
219 SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack =
220 MAKELONG(getSP() + (STACK_FLAGS + 1) * 2, getSS());
221
222 /* Check the value in the AH register */
223 switch (getAH())
224 {
225 /* Terminate Program */
226 case 0x00:
227 {
228 /* CS must be the PSP segment */
230 break;
231 }
232
233 /* Read Character from STDIN with Echo */
234 case 0x01:
235 {
236 DPRINT("INT 21h, AH = 01h\n");
237
239 if (Character == 0x03 && DosControlBreak()) break;
240
241 setAL(Character);
242 break;
243 }
244
245 /* Write Character to STDOUT */
246 case 0x02:
247 {
248 // FIXME: Under DOS 2+, output handle may be redirected!!!!
249 Character = getDL();
251
252 /*
253 * We return the output character (DOS 2.1+).
254 * Also, if we're going to output a TAB, then
255 * don't return a TAB but a SPACE instead.
256 * See Ralf Brown: http://www.ctyme.com/intr/rb-2554.htm
257 * for more information.
258 */
259 setAL(Character == '\t' ? ' ' : Character);
260 break;
261 }
262
263 /* Read Character from STDAUX */
264 case 0x03:
265 {
266 // FIXME: Really read it from STDAUX!
267 DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
268 // setAL(DosReadCharacter());
269 break;
270 }
271
272 /* Write Character to STDAUX */
273 case 0x04:
274 {
275 // FIXME: Really write it to STDAUX!
276 DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
277 // DosPrintCharacter(getDL());
278 break;
279 }
280
281 /* Write Character to Printer */
282 case 0x05:
283 {
284 // FIXME: Really write it to printer!
285 DPRINT1("INT 16h, 05h: Write character to printer is HALFPLEMENTED -\n\n");
286 DPRINT1("0x%p\n", getDL());
287 DPRINT1("\n\n-----------\n\n");
288 break;
289 }
290
291 /* Direct Console I/O */
292 case 0x06:
293 {
294 Character = getDL();
295
296 // FIXME: Under DOS 2+, output handle may be redirected!!!!
297
298 if (Character != 0xFF)
299 {
300 /* Output */
302
303 /*
304 * We return the output character (DOS 2.1+).
305 * See Ralf Brown: http://www.ctyme.com/intr/rb-2558.htm
306 * for more information.
307 */
308 setAL(Character);
309 }
310 else
311 {
312 /* Input */
313 if (DosCheckInput())
314 {
315 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
317 }
318 else
319 {
320 /* No character available */
322 setAL(0x00);
323 }
324 }
325
326 break;
327 }
328
329 /* Direct Character Input without Echo */
330 case 0x07:
331 {
332 DPRINT("Direct char input without echo\n");
334 break;
335 }
336
337 /* Character Input without Echo */
338 case 0x08:
339 {
340 DPRINT("Char input without echo\n");
341
343 if (Character == 0x03 && DosControlBreak()) break;
344
345 setAL(Character);
346 break;
347 }
348
349 /* Write String to STDOUT */
350 case 0x09:
351 {
353
354 while (*String != '$')
355 {
357 String++;
358 }
359
360 /*
361 * We return the terminating character (DOS 2.1+).
362 * See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
363 * for more information.
364 */
365 setAL('$'); // *String
366 break;
367 }
368
369 /* Read Buffered Input */
370 case 0x0A:
371 {
373
374 DPRINT("Read Buffered Input\n");
375 if (InputBuffer->MaxLength == 0) break;
376
377 /* Read from standard input */
381 InputBuffer->MaxLength
382 );
383
384 break;
385 }
386
387 /* Get STDIN Status */
388 case 0x0B:
389 {
390 setAL(DosCheckInput() ? 0xFF : 0x00);
391 break;
392 }
393
394 /* Flush Buffer and Read STDIN */
395 case 0x0C:
396 {
397 BYTE InputFunction = getAL();
398
399 /* Flush STDIN buffer */
401
402 /*
403 * If the input function number contained in AL is valid, i.e.
404 * AL == 0x01 or 0x06 or 0x07 or 0x08 or 0x0A, call ourselves
405 * recursively with AL == AH.
406 */
407 if (InputFunction == 0x01 || InputFunction == 0x06 ||
408 InputFunction == 0x07 || InputFunction == 0x08 ||
409 InputFunction == 0x0A)
410 {
411 /* Call ourselves recursively */
412 setAH(InputFunction);
414 }
415 break;
416 }
417
418 /* Disk Reset */
419 case 0x0D:
420 {
422
423 // TODO: Flush what's needed.
424 DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
425
426 /* Clear CF in DOS 6 only */
427 if (PspBlock->DosVersion == 0x0006)
428 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
429
430 break;
431 }
432
433 /* Set Default Drive */
434 case 0x0E:
435 {
438 break;
439 }
440
441 /* NULL Function for CP/M Compatibility */
442 case 0x18:
443 {
444 /*
445 * This function corresponds to the CP/M BDOS function
446 * "get bit map of logged drives", which is meaningless
447 * under MS-DOS.
448 *
449 * For: PTS-DOS 6.51 & S/DOS 1.0 - EXTENDED RENAME FILE USING FCB
450 * See Ralf Brown: http://www.ctyme.com/intr/rb-2584.htm
451 * for more information.
452 */
453 setAL(0x00);
454 break;
455 }
456
457 /* Get Default Drive */
458 case 0x19:
459 {
461 break;
462 }
463
464 /* Set Disk Transfer Area */
465 case 0x1A:
466 {
468 break;
469 }
470
471 /* NULL Function for CP/M Compatibility */
472 case 0x1D:
473 case 0x1E:
474 {
475 /*
476 * Function 0x1D corresponds to the CP/M BDOS function
477 * "get bit map of read-only drives", which is meaningless
478 * under MS-DOS.
479 * See Ralf Brown: http://www.ctyme.com/intr/rb-2592.htm
480 * for more information.
481 *
482 * Function 0x1E corresponds to the CP/M BDOS function
483 * "set file attributes", which was meaningless under MS-DOS 1.x.
484 * See Ralf Brown: http://www.ctyme.com/intr/rb-2593.htm
485 * for more information.
486 */
487 setAL(0x00);
488 break;
489 }
490
491 /* NULL Function for CP/M Compatibility */
492 case 0x20:
493 {
494 /*
495 * This function corresponds to the CP/M BDOS function
496 * "get/set default user (sublibrary) number", which is meaningless
497 * under MS-DOS.
498 *
499 * For: S/DOS 1.0+ & PTS-DOS 6.51+ - GET OEM REVISION
500 * See Ralf Brown: http://www.ctyme.com/intr/rb-2596.htm
501 * for more information.
502 */
503 setAL(0x00);
504 break;
505 }
506
507 /* Set Interrupt Vector */
508 case 0x25:
509 {
510 ULONG FarPointer = MAKELONG(getDX(), getDS());
511 DPRINT1("Setting interrupt 0x%02X to %04X:%04X ...\n",
512 getAL(), HIWORD(FarPointer), LOWORD(FarPointer));
513
514 /* Write the new far pointer to the IDT */
515 ((PULONG)BaseAddress)[getAL()] = FarPointer;
516 break;
517 }
518
519 /* Create New PSP */
520 case 0x26:
521 {
522 /* DOS 2+ assumes that the caller's CS is the segment of the PSP to copy */
524 break;
525 }
526
527 /* Parse Filename into FCB */
528 case 0x29:
529 {
532 BYTE Options = getAL();
533 CHAR FillChar = ' ';
534 UINT i;
535
536 if (FileName[1] == ':')
537 {
538 /* Set the drive number */
539 Fcb->DriveNumber = RtlUpperChar(FileName[0]) - 'A' + 1;
540
541 /* Skip to the file name part */
542 FileName += 2;
543 }
544 else
545 {
546 /* No drive number specified */
547 if (Options & (1 << 1)) Fcb->DriveNumber = Sda->CurrentDrive + 1;
548 else Fcb->DriveNumber = 0;
549 }
550
551 /* Parse the file name */
552 i = 0;
553 while ((*FileName > 0x20) && (i < 8))
554 {
555 if (*FileName == '.') break;
556 else if (*FileName == '*')
557 {
558 FillChar = '?';
559 break;
560 }
561
562 Fcb->FileName[i++] = RtlUpperChar(*FileName++);
563 }
564
565 /* Fill the whole field with blanks only if bit 2 is not set */
566 if ((FillChar != ' ') || (i != 0) || !(Options & (1 << 2)))
567 {
568 for (; i < 8; i++) Fcb->FileName[i] = FillChar;
569 }
570
571 /* Skip to the extension part */
572 while (*FileName > 0x20 && *FileName != '.') FileName++;
573 if (*FileName == '.') FileName++;
574
575 /* Now parse the extension */
576 i = 0;
577 FillChar = ' ';
578
579 while ((*FileName > 0x20) && (i < 3))
580 {
581 if (*FileName == '*')
582 {
583 FillChar = '?';
584 break;
585 }
586
587 Fcb->FileExt[i++] = RtlUpperChar(*FileName++);
588 }
589
590 /* Fill the whole field with blanks only if bit 3 is not set */
591 if ((FillChar != ' ') || (i != 0) || !(Options & (1 << 3)))
592 {
593 for (; i < 3; i++) Fcb->FileExt[i] = FillChar;
594 }
595
596 break;
597 }
598
599 /* Get System Date */
600 case 0x2A:
601 {
602 GetLocalTime(&SystemTime);
603 setCX(SystemTime.wYear);
604 setDX(MAKEWORD(SystemTime.wDay, SystemTime.wMonth));
605 setAL(SystemTime.wDayOfWeek);
606 break;
607 }
608
609 /* Set System Date */
610 case 0x2B:
611 {
612 GetLocalTime(&SystemTime);
613 SystemTime.wYear = getCX();
614 SystemTime.wMonth = getDH();
615 SystemTime.wDay = getDL();
616
617 /* Return success or failure */
618 setAL(SetLocalTime(&SystemTime) ? 0x00 : 0xFF);
619 break;
620 }
621
622 /* Get System Time */
623 case 0x2C:
624 {
625 GetLocalTime(&SystemTime);
626 setCX(MAKEWORD(SystemTime.wMinute, SystemTime.wHour));
627 setDX(MAKEWORD(SystemTime.wMilliseconds / 10, SystemTime.wSecond));
628 break;
629 }
630
631 /* Set System Time */
632 case 0x2D:
633 {
634 GetLocalTime(&SystemTime);
635 SystemTime.wHour = getCH();
636 SystemTime.wMinute = getCL();
637 SystemTime.wSecond = getDH();
638 SystemTime.wMilliseconds = getDL() * 10; // In hundredths of seconds
639
640 /* Return success or failure */
641 setAL(SetLocalTime(&SystemTime) ? 0x00 : 0xFF);
642 break;
643 }
644
645 /* Get Disk Transfer Area */
646 case 0x2F:
647 {
650 break;
651 }
652
653 /* Get DOS Version */
654 case 0x30:
655 {
657
658 /*
659 * DOS 2+ - GET DOS VERSION
660 * See Ralf Brown: http://www.ctyme.com/intr/rb-2711.htm
661 * for more information.
662 */
663
664 if (LOBYTE(PspBlock->DosVersion) < 5 || getAL() == 0x00)
665 {
666 /*
667 * Return DOS OEM number:
668 * 0x00 for IBM PC-DOS
669 * 0x02 for packaged MS-DOS
670 * 0xFF for NT DOS
671 */
672 setBH(0xFF);
673 }
674
675 if (LOBYTE(PspBlock->DosVersion) >= 5 && getAL() == 0x01)
676 {
677 /*
678 * Return version flag:
679 * 1 << 3 if DOS is in ROM,
680 * 0 (reserved) if not.
681 */
682 setBH(0x00);
683 }
684
685 /* Return DOS 24-bit user serial number in BL:CX */
686 setBL(0x00);
687 setCX(0x0000);
688
689 /*
690 * Return DOS version: Minor:Major in AH:AL
691 * The Windows NT DOS box returns version 5.00, subject to SETVER.
692 */
693 setAX(PspBlock->DosVersion);
694
695 break;
696 }
697
698 /* Terminate and Stay Resident */
699 case 0x31:
700 {
701 DPRINT1("Process going resident: %u paragraphs kept\n", getDX());
703 break;
704 }
705
706 /* Extended functionalities */
707 case 0x33:
708 {
709 switch (getAL())
710 {
711 /*
712 * DOS 4+ - GET BOOT DRIVE
713 */
714 case 0x05:
715 {
717 break;
718 }
719
720 /*
721 * DOS 5+ - GET TRUE VERSION NUMBER
722 * This function always returns the true version number, unlike
723 * AH=30h, whose return value may be changed with SETVER.
724 * See Ralf Brown: http://www.ctyme.com/intr/rb-2730.htm
725 * for more information.
726 */
727 case 0x06:
728 {
729 /*
730 * Return the true DOS version: Minor:Major in BH:BL
731 * The Windows NT DOS box returns BX=3205h (version 5.50).
732 */
734
735 /* DOS revision 0 */
736 setDL(0x00);
737
738 /* Unpatched DOS */
739 setDH(0x00);
740
741 break;
742 }
743
744 default: // goto Default;
745 {
746 DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
747 getAH(), getAL());
748 }
749 }
750
751 break;
752 }
753
754 /* Get Address of InDOS flag */
755 case 0x34:
756 {
759 break;
760 }
761
762 /* Get Interrupt Vector */
763 case 0x35:
764 {
765 ULONG FarPointer = ((PULONG)BaseAddress)[getAL()];
766
767 /* Read the address from the IDT into ES:BX */
768 setES(HIWORD(FarPointer));
769 setBX(LOWORD(FarPointer));
770 break;
771 }
772
773 /* Get Free Disk Space */
774 case 0x36:
775 {
776 CHAR RootPath[] = "?:\\";
777 DWORD SectorsPerCluster;
778 DWORD BytesPerSector;
779 DWORD NumberOfFreeClusters;
780 DWORD TotalNumberOfClusters;
781
782 if (getDL() == 0x00)
783 RootPath[0] = 'A' + Sda->CurrentDrive;
784 else
785 RootPath[0] = 'A' + getDL() - 1;
786
787 if (GetDiskFreeSpaceA(RootPath,
788 &SectorsPerCluster,
789 &BytesPerSector,
790 &NumberOfFreeClusters,
791 &TotalNumberOfClusters))
792 {
793 setAX(LOWORD(SectorsPerCluster));
794 setCX(LOWORD(BytesPerSector));
795 setBX(min(NumberOfFreeClusters, 0xFFFF));
796 setDX(min(TotalNumberOfClusters, 0xFFFF));
797 }
798 else
799 {
800 /* Error */
801 setAX(0xFFFF);
802 }
803
804 break;
805 }
806
807 /* SWITCH character - AVAILDEV */
808 case 0x37:
809 {
810 switch (getAL())
811 {
812 /*
813 * DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER
814 * This setting is ignored by MS-DOS 4.0+.
815 * MS-DOS 5+ always return AL=00h/DL=2Fh.
816 * See Ralf Brown: http://www.ctyme.com/intr/rb-2752.htm
817 * for more information.
818 */
819 case 0x00:
820 setDL('/');
821 setAL(0x00);
822 break;
823
824 /*
825 * DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER
826 * This setting is ignored by MS-DOS 5+.
827 * See Ralf Brown: http://www.ctyme.com/intr/rb-2753.htm
828 * for more information.
829 */
830 case 0x01:
831 // getDL();
832 setAL(0xFF);
833 break;
834
835 /*
836 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
837 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
838 * for more information.
839 */
840 case 0x02:
841 // setDL();
842 setAL(0xFF);
843 break;
844
845 /*
846 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
847 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
848 * for more information.
849 */
850 case 0x03:
851 // getDL();
852 setAL(0xFF);
853 break;
854
855 /* Invalid subfunction */
856 default:
857 setAL(0xFF);
858 break;
859 }
860
861 break;
862 }
863
864 /* Get/Set Country-dependent Information */
865 case 0x38:
866 {
867 WORD CountryId = getAL() < 0xFF ? getAL() : getBX();
869
870 ErrorCode = DosGetCountryInfo(&CountryId,
872
874 {
875 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
876 setBX(CountryId);
877 }
878 else
879 {
882 }
883
884 break;
885 }
886
887 /* Create Directory */
888 case 0x39:
889 {
891
893 {
894 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
895 }
896 else
897 {
900 }
901
902 break;
903 }
904
905 /* Remove Directory */
906 case 0x3A:
907 {
909
911 {
912 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
913 }
914 else
915 {
918 }
919
920 break;
921 }
922
923 /* Set Current Directory */
924 case 0x3B:
925 {
927
929 {
930 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
931 }
932 else
933 {
936 }
937
938 break;
939 }
940
941 /* Create or Truncate File */
942 case 0x3C:
943 {
948 getCX());
949
951 {
952 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
954 }
955 else
956 {
959 }
960
961 break;
962 }
963
964 /* Open File or Device */
965 case 0x3D:
966 {
968 BYTE AccessShareModes = getAL();
970 WORD ErrorCode = DosOpenFile(&FileHandle, FileName, AccessShareModes);
971
972 /*
973 * Check if we failed because we attempted to open a file for write
974 * on a CDROM drive. In that situation, attempt to reopen for read
975 */
977 (AccessShareModes & 0x03) != 0 && DosIsFileOnCdRom())
978 {
980 }
981
983 {
984 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
986 }
987 else
988 {
991 }
992
993 break;
994 }
995
996 /* Close File or Device */
997 case 0x3E:
998 {
999 if (DosCloseHandle(getBX()))
1000 {
1001 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1002 }
1003 else
1004 {
1007 }
1008
1009 break;
1010 }
1011
1012 /* Read from File or Device */
1013 case 0x3F:
1014 {
1015 WORD BytesRead = 0;
1017
1018 DPRINT("DosReadFile(0x%04X)\n", getBX());
1019
1021 MAKELONG(getDX(), getDS()),
1022 getCX(),
1023 &BytesRead);
1024
1025 if (ErrorCode == ERROR_SUCCESS)
1026 {
1027 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1029 }
1030 else if (ErrorCode != ERROR_NOT_READY)
1031 {
1034 }
1035
1036 break;
1037 }
1038
1039 /* Write to File or Device */
1040 case 0x40:
1041 {
1042 WORD BytesWritten = 0;
1044 MAKELONG(getDX(), getDS()),
1045 getCX(),
1046 &BytesWritten);
1047
1048 if (ErrorCode == ERROR_SUCCESS)
1049 {
1050 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1052 }
1053 else
1054 {
1057 }
1058
1059 break;
1060 }
1061
1062 /* Delete File */
1063 case 0x41:
1064 {
1066
1068 {
1069 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1070 /*
1071 * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
1072 * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
1073 */
1074 setAL(RtlUpperChar(FileName[0]) - 'A');
1075 }
1076 else
1077 {
1080 }
1081
1082 break;
1083 }
1084
1085 /* Seek File */
1086 case 0x42:
1087 {
1088 DWORD NewLocation;
1090 MAKELONG(getDX(), getCX()),
1091 getAL(),
1092 &NewLocation);
1093
1094 if (ErrorCode == ERROR_SUCCESS)
1095 {
1096 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1097
1098 /* Return the new offset in DX:AX */
1099 setDX(HIWORD(NewLocation));
1100 setAX(LOWORD(NewLocation));
1101 }
1102 else
1103 {
1106 }
1107
1108 break;
1109 }
1110
1111 /* Get/Set File Attributes */
1112 case 0x43:
1113 {
1116
1117 if (getAL() == 0x00)
1118 {
1119 /* Get the attributes */
1121
1122 /* Check if it failed */
1124 {
1127 }
1128 else
1129 {
1130 /* Return the attributes that DOS can understand */
1131 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1132 setCX(Attributes & 0x00FF);
1133 }
1134 }
1135 else if (getAL() == 0x01)
1136 {
1137 /* Try to set the attributes */
1139 {
1140 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1141 }
1142 else
1143 {
1146 }
1147 }
1148 else
1149 {
1152 }
1153
1154 break;
1155 }
1156
1157 /* IOCTL */
1158 case 0x44:
1159 {
1160 WORD Length = getCX();
1161
1163 {
1164 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1165 setAX(Length);
1166 }
1167 else
1168 {
1171 }
1172
1173 break;
1174 }
1175
1176 /* Duplicate Handle */
1177 case 0x45:
1178 {
1179 WORD NewHandle = DosDuplicateHandle(getBX());
1180
1181 if (NewHandle != INVALID_DOS_HANDLE)
1182 {
1183 setAX(NewHandle);
1184 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1185 }
1186 else
1187 {
1190 }
1191
1192 break;
1193 }
1194
1195 /* Force Duplicate Handle */
1196 case 0x46:
1197 {
1199 {
1200 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1201 }
1202 else
1203 {
1206 }
1207
1208 break;
1209 }
1210
1211 /* Get Current Directory */
1212 case 0x47:
1213 {
1214 BYTE DriveNumber = getDL();
1216
1217 /* Get the real drive number */
1218 if (DriveNumber == 0)
1219 {
1220 DriveNumber = Sda->CurrentDrive;
1221 }
1222 else
1223 {
1224 /* Decrement DriveNumber since it was 1-based */
1225 DriveNumber--;
1226 }
1227
1228 if (DriveNumber < SysVars->NumLocalDrives)
1229 {
1230 /*
1231 * Copy the current directory into the target buffer.
1232 * It doesn't contain the drive letter and the backslash.
1233 */
1235 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1236 setAX(0x0100); // Undocumented, see Ralf Brown: http://www.ctyme.com/intr/rb-2933.htm
1237 }
1238 else
1239 {
1242 }
1243
1244 break;
1245 }
1246
1247 /* Allocate Memory */
1248 case 0x48:
1249 {
1250 WORD MaxAvailable = 0;
1251 WORD Segment = DosAllocateMemory(getBX(), &MaxAvailable);
1252
1253 if (Segment != 0)
1254 {
1255 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1256 setAX(Segment);
1257 }
1258 else
1259 {
1262 setBX(MaxAvailable);
1263 }
1264
1265 break;
1266 }
1267
1268 /* Free Memory */
1269 case 0x49:
1270 {
1271 if (DosFreeMemory(getES()))
1272 {
1273 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1274 }
1275 else
1276 {
1279 }
1280
1281 break;
1282 }
1283
1284 /* Resize Memory Block */
1285 case 0x4A:
1286 {
1287 WORD Size;
1288
1289 if (DosResizeMemory(getES(), getBX(), &Size))
1290 {
1291 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1292 }
1293 else
1294 {
1297 setBX(Size);
1298 }
1299
1300 break;
1301 }
1302
1303 /* Execute */
1304 case 0x4B:
1305 {
1306 BYTE OrgAL = getAL();
1307 LPSTR ProgramName = SEG_OFF_TO_PTR(getDS(), getDX());
1310
1311 if (OrgAL <= DOS_LOAD_OVERLAY)
1312 {
1313 DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)OrgAL;
1314
1315 if (LoadType == DOS_LOAD_AND_EXECUTE)
1316 {
1317 /* Create a new process */
1318 ErrorCode = DosCreateProcess(ProgramName,
1319 ParamBlock,
1321 }
1322 else
1323 {
1324 /* Just load an executable */
1325 ErrorCode = DosLoadExecutable(LoadType,
1326 ProgramName,
1327 ParamBlock,
1328 NULL,
1329 NULL,
1331 }
1332 }
1333 else if (OrgAL == 0x05)
1334 {
1335 // http://www.ctyme.com/intr/rb-2942.htm
1336 DPRINT1("Set execution state is UNIMPLEMENTED\n");
1338 }
1339 else
1340 {
1342 }
1343
1344 if (ErrorCode == ERROR_SUCCESS)
1345 {
1346 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1347 }
1348 else
1349 {
1352 }
1353
1354 break;
1355 }
1356
1357 /* Terminate with Return Code */
1358 case 0x4C:
1359 {
1361 break;
1362 }
1363
1364 /* Get Return Code (ERRORLEVEL) */
1365 case 0x4D:
1366 {
1367 /*
1368 * According to Ralf Brown: http://www.ctyme.com/intr/rb-2976.htm
1369 * DosErrorLevel is cleared after being read by this function.
1370 */
1371 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1373 Sda->ErrorLevel = 0x0000; // Clear it
1374 break;
1375 }
1376
1377 /* Find First File */
1378 case 0x4E:
1379 {
1382 getCX());
1383
1384 setAX(Result);
1385
1386 if (Result == ERROR_SUCCESS)
1387 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1388 else
1390
1391 break;
1392 }
1393
1394 /* Find Next File */
1395 case 0x4F:
1396 {
1398
1399 setAX(Result);
1400
1401 if (Result == ERROR_SUCCESS)
1402 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1403 else
1405
1406 break;
1407 }
1408
1409 /* Internal - Set Current Process ID (Set PSP Address) */
1410 case 0x50:
1411 {
1413 break;
1414 }
1415
1416 /* Internal - Get Current Process ID (Get PSP Address) */
1417 case 0x51:
1418 /* Get Current PSP Address */
1419 case 0x62:
1420 {
1421 /*
1422 * Undocumented AH=51h is identical to the documented AH=62h.
1423 * See Ralf Brown: http://www.ctyme.com/intr/rb-2982.htm
1424 * and http://www.ctyme.com/intr/rb-3140.htm
1425 * for more information.
1426 */
1428 break;
1429 }
1430
1431 /* Internal - Get "List of lists" (SYSVARS) */
1432 case 0x52:
1433 {
1434 /*
1435 * On return, ES points at the DOS data segment (see also INT 2F/AX=1203h).
1436 * See Ralf Brown: http://www.ctyme.com/intr/rb-2983.htm
1437 * for more information.
1438 */
1439
1440 /* Return the DOS "list of lists" in ES:BX */
1443 break;
1444 }
1445
1446 /* Create Child PSP */
1447 case 0x55:
1448 {
1449 DosCreatePsp(getDX(), getSI());
1451 break;
1452 }
1453
1454 /* Rename File */
1455 case 0x56:
1456 {
1457 LPSTR ExistingFileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
1458 LPSTR NewFileName = (LPSTR)SEG_OFF_TO_PTR(getES(), getDI());
1459
1460 /*
1461 * See Ralf Brown: http://www.ctyme.com/intr/rb-2990.htm
1462 * for more information.
1463 */
1464
1465 if (MoveFileA(ExistingFileName, NewFileName))
1466 {
1467 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1468 }
1469 else
1470 {
1473 }
1474
1475 break;
1476 }
1477
1478 /* File Attributes */
1479 case 0x57:
1480 {
1481 switch (getAL())
1482 {
1483 /* Get File's last-written Date and Time */
1484 case 0x00:
1485 {
1487 FILETIME LastWriteTime;
1488 WORD FileDate, FileTime;
1489
1490 if (Descriptor == NULL)
1491 {
1492 /* Invalid handle */
1494 // Sda->LastErrorCode = ERROR_INVALID_HANDLE;
1496 break;
1497 }
1498
1499 if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
1500 {
1501 /* Invalid for devices */
1503 // setAX(ERROR_INVALID_FUNCTION);
1505 break;
1506 }
1507
1508 /*
1509 * Retrieve the last-written Win32 date and time,
1510 * and convert it to DOS format.
1511 */
1512 if (!GetFileTime(Descriptor->Win32Handle,
1513 NULL, NULL, &LastWriteTime) ||
1514 !FileTimeToDosDateTime(&LastWriteTime,
1515 &FileDate, &FileTime))
1516 {
1519 break;
1520 }
1521
1522 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1523 setCX(FileTime);
1524 setDX(FileDate);
1525 break;
1526 }
1527
1528 /* Set File's last-written Date and Time */
1529 case 0x01:
1530 {
1532 FILETIME LastWriteTime;
1533 WORD FileDate = getDX();
1534 WORD FileTime = getCX();
1535
1536 if (Descriptor == NULL)
1537 {
1538 /* Invalid handle */
1540 // Sda->LastErrorCode = ERROR_INVALID_HANDLE;
1542 break;
1543 }
1544
1545 if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
1546 {
1547 /* Invalid for devices */
1549 // setAX(ERROR_INVALID_FUNCTION);
1551 break;
1552 }
1553
1554 /*
1555 * Convert the new last-written DOS date and time
1556 * to Win32 format and set it.
1557 */
1558 if (!DosDateTimeToFileTime(FileDate, FileTime,
1559 &LastWriteTime) ||
1560 !SetFileTime(Descriptor->Win32Handle,
1561 NULL, NULL, &LastWriteTime))
1562 {
1565 break;
1566 }
1567
1568 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1569 break;
1570 }
1571
1572 default: // goto Default;
1573 {
1574 DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
1575 getAH(), getAL());
1576 }
1577 }
1578
1579 break;
1580 }
1581
1582 /* Get/Set Memory Management Options */
1583 case 0x58:
1584 {
1585 switch (getAL())
1586 {
1587 /* Get allocation strategy */
1588 case 0x00:
1589 {
1590 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1592 break;
1593 }
1594
1595 /* Set allocation strategy */
1596 case 0x01:
1597 {
1600 {
1601 /* Can't set both */
1604 break;
1605 }
1606
1609 {
1610 /* Invalid allocation strategy */
1613 break;
1614 }
1615
1616 Sda->AllocStrategy = getBL();
1617 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1618 break;
1619 }
1620
1621 /* Get UMB link state */
1622 case 0x02:
1623 {
1624 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1625 setAL(SysVars->UmbLinked ? 0x01 : 0x00);
1626 break;
1627 }
1628
1629 /* Set UMB link state */
1630 case 0x03:
1631 {
1633
1634 if (getBX())
1635 Success = DosLinkUmb();
1636 else
1638
1639 if (Success)
1640 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1641 else
1643
1644 break;
1645 }
1646
1647 /* Invalid or unsupported function */
1648 default:
1649 {
1652 }
1653 }
1654
1655 break;
1656 }
1657
1658 /* Get Extended Error Information */
1659 case 0x59:
1660 {
1661 DPRINT1("INT 21h, AH = 59h, BX = %04Xh - Get Extended Error Information is UNIMPLEMENTED\n",
1662 getBX());
1663 break;
1664 }
1665
1666 /* Create Temporary File */
1667 case 0x5A:
1668 {
1669 LPSTR PathName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
1670 LPSTR FileName = PathName; // The buffer for the path and the full file name is the same.
1671 UINT uRetVal;
1674
1675 /*
1676 * See Ralf Brown: http://www.ctyme.com/intr/rb-3014.htm
1677 * for more information.
1678 */
1679
1680 // FIXME: Check for buffer validity?
1681 // It should be a ASCIIZ path ending with a '\' + 13 zero bytes
1682 // to receive the generated filename.
1683
1684 /* First create the temporary file */
1685 uRetVal = GetTempFileNameA(PathName, NULL, 0, FileName);
1686 if (uRetVal == 0)
1687 {
1690 break;
1691 }
1692
1693 /* Now try to open it in read/write access */
1695 if (ErrorCode == ERROR_SUCCESS)
1696 {
1697 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1699 }
1700 else
1701 {
1704 }
1705
1706 break;
1707 }
1708
1709 /* Create New File */
1710 case 0x5B:
1711 {
1715 CREATE_NEW,
1716 getCX());
1717
1718 if (ErrorCode == ERROR_SUCCESS)
1719 {
1720 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1722 }
1723 else
1724 {
1727 }
1728
1729 break;
1730 }
1731
1732 /* Lock/Unlock Region of File */
1733 case 0x5C:
1734 {
1735 if (getAL() == 0x00)
1736 {
1737 /* Lock region of file */
1738 if (DosLockFile(getBX(), MAKELONG(getDX(), getCX()), MAKELONG(getDI(), getSI())))
1739 {
1740 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1741 }
1742 else
1743 {
1746 }
1747 }
1748 else if (getAL() == 0x01)
1749 {
1750 /* Unlock region of file */
1752 {
1753 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1754 }
1755 else
1756 {
1759 }
1760 }
1761 else
1762 {
1763 /* Invalid subfunction */
1766 }
1767
1768 break;
1769 }
1770
1771 /* Canonicalize File Name or Path */
1772 case 0x60:
1773 {
1774 /*
1775 * See Ralf Brown: http://www.ctyme.com/intr/rb-3137.htm
1776 * for more information.
1777 */
1778
1779 /*
1780 * We suppose that the DOS app gave to us a valid
1781 * 128-byte long buffer for the canonicalized name.
1782 */
1784 128,
1786 NULL);
1787 if (dwRetVal == 0)
1788 {
1791 }
1792 else
1793 {
1794 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1795 setAX(0x0000);
1796 }
1797
1798 // FIXME: Convert the full path name into short version.
1799 // We cannot reliably use GetShortPathName, because it fails
1800 // if the path name given doesn't exist. However this DOS
1801 // function AH=60h should be able to work even for non-existing
1802 // path and file names.
1803
1804 break;
1805 }
1806
1807 /* Miscellaneous Internal Functions */
1808 case 0x5D:
1809 {
1810 switch (getAL())
1811 {
1812 /* Get Swappable Data Area */
1813 case 0x06:
1814 {
1817 setCX(sizeof(DOS_SDA));
1818 setDX(FIELD_OFFSET(DOS_SDA, LastAX));
1819
1820 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1821 break;
1822 }
1823
1824 default: // goto Default;
1825 {
1826 DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
1827 getAH(), getAL());
1828 }
1829 }
1830
1831 break;
1832 }
1833
1834 /* Extended Country Information */
1835 case 0x65:
1836 {
1837 switch (getAL())
1838 {
1839 case 0x01: case 0x02: case 0x03:
1840 case 0x04: case 0x05: case 0x06:
1841 case 0x07:
1842 {
1843 WORD BufferSize = getCX();
1846 getBX(),
1847 getDX(),
1849 &BufferSize);
1850 if (ErrorCode == ERROR_SUCCESS)
1851 {
1852 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1854 }
1855 else
1856 {
1859 }
1860
1861 break;
1862 }
1863
1864 /* Country-dependent Character Capitalization -- Character */
1865 case 0x20:
1866 /* Country-dependent Filename Capitalization -- Character */
1867 case 0xA0:
1868 {
1870 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1871 // setAX(ERROR_SUCCESS);
1872 break;
1873 }
1874
1875 /* Country-dependent Character Capitalization -- Counted ASCII String */
1876 case 0x21:
1877 /* Country-dependent Filename Capitalization -- Counted ASCII String */
1878 case 0xA1:
1879 {
1881 // FIXME: Check for NULL ptr!!
1883 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1884 // setAX(ERROR_SUCCESS);
1885 break;
1886 }
1887
1888 /* Country-dependent Character Capitalization -- ASCIIZ String */
1889 case 0x22:
1890 /* Country-dependent Filename Capitalization -- ASCIIZ String */
1891 case 0xA2:
1892 {
1894 // FIXME: Check for NULL ptr!!
1896 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1897 // setAX(ERROR_SUCCESS);
1898 break;
1899 }
1900
1901 /* Determine if Character represents YES/NO Response */
1902 case 0x23:
1903 {
1905 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1906 break;
1907 }
1908
1909 default: // goto Default;
1910 {
1911 DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
1912 getAH(), getAL());
1913 }
1914 }
1915
1916 break;
1917 }
1918
1919 /* Set Handle Count */
1920 case 0x67:
1921 {
1923 {
1926 }
1927 else Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1928
1929 break;
1930 }
1931
1932 /* Commit File */
1933 case 0x68:
1934 case 0x6A:
1935 {
1936 /*
1937 * Function 6Ah is identical to function 68h,
1938 * and sets AH to 68h if success.
1939 * See Ralf Brown: http://www.ctyme.com/intr/rb-3176.htm
1940 * for more information.
1941 */
1942 setAH(0x68);
1943
1945 {
1946 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1947 }
1948 else
1949 {
1952 }
1953
1954 break;
1955 }
1956
1957 /* Extended Open/Create */
1958 case 0x6C:
1959 {
1961 WORD CreationStatus;
1963
1964 /* Check for AL == 00 */
1965 if (getAL() != 0x00)
1966 {
1969 break;
1970 }
1971
1972 /*
1973 * See Ralf Brown: http://www.ctyme.com/intr/rb-3179.htm
1974 * for the full detailed description.
1975 *
1976 * WARNING: BH contains some extended flags that are NOT SUPPORTED.
1977 */
1978
1980 &CreationStatus,
1982 getBL(),
1983 getDL(),
1984 getCX());
1985
1986 if (ErrorCode == ERROR_SUCCESS)
1987 {
1988 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1989 setCX(CreationStatus);
1991 }
1992 else
1993 {
1996 }
1997
1998 break;
1999 }
2000
2001 /* Long FileName Support */
2002 case 0x71:
2003 {
2004 DPRINT1("INT 21h LFN Support, AH = %02Xh, AL = %02Xh NOT IMPLEMENTED!\n",
2005 getAH(), getAL());
2006
2007 setAL(0); // Some functions expect AL to be 0 when it's not supported.
2009 break;
2010 }
2011
2012 /* Unsupported */
2013 default: // Default:
2014 {
2015 DPRINT1("DOS Function INT 21h, AH = %02Xh, AL = %02Xh NOT IMPLEMENTED!\n",
2016 getAH(), getAL());
2017
2018 setAL(0); // Some functions expect AL to be 0 when it's not supported.
2020 }
2021 }
2022
2023 Sda->InDos--;
2024}
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
_In_ PFCB Fcb
Definition: cdprocs.h:159
Definition: bufpool.h:45
WORD DosIfCharYesNo(WORD Char)
Definition: country.c:204
VOID DosToUpperStrZ(PSTR DestStr, PSTR SrcStr)
Definition: country.c:230
WORD DosGetCountryInfoEx(IN BYTE InfoId, IN WORD CodePage, IN WORD CountryId, OUT PDOS_COUNTRY_INFO_2 CountryInfo, IN OUT PWORD BufferSize)
Definition: country.c:141
WORD DosGetCountryInfo(IN OUT PWORD CountryId, OUT PDOS_COUNTRY_INFO CountryInfo)
Definition: country.c:77
CHAR DosToUpper(CHAR Char)
Definition: country.c:218
VOID DosToUpperStrN(PCHAR DestStr, PCHAR SrcStr, WORD Length)
Definition: country.c:224
#define ERROR_INVALID_FUNCTION
Definition: dderror.h:6
DWORD WINAPI demFileFindFirst(_Out_ PVOID pFindFileData, _In_ PCSTR FileName, _In_ WORD AttribMask)
Definition: dem.c:1515
DWORD WINAPI demFileFindNext(_Inout_ PVOID pFindFileData)
Definition: dem.c:1592
DWORD WINAPI demFileDelete(IN LPCSTR FileName)
Definition: dem.c:1402
#define ERROR_SUCCESS
Definition: deptool.c:10
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:102
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
BOOL WINAPI RemoveDirectoryA(IN LPCSTR lpPathName)
Definition: dir.c:714
BOOL WINAPI CreateDirectoryA(IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:37
BOOL WINAPI GetDiskFreeSpaceA(IN LPCSTR lpRootPathName, OUT LPDWORD lpSectorsPerCluster, OUT LPDWORD lpBytesPerSector, OUT LPDWORD lpNumberOfFreeClusters, OUT LPDWORD lpTotalNumberOfClusters)
Definition: disk.c:142
BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:776
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:948
BOOL WINAPI GetFileTime(IN HANDLE hFile, OUT LPFILETIME lpCreationTime OPTIONAL, OUT LPFILETIME lpLastAccessTime OPTIONAL, OUT LPFILETIME lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:896
BOOL WINAPI MoveFileA(IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName)
Definition: move.c:1137
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:993
BOOL WINAPI SetLocalTime(IN CONST SYSTEMTIME *lpSystemTime)
Definition: time.c:356
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:286
BOOL WINAPI FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime, OUT LPWORD lpFatDate, OUT LPWORD lpFatTime)
Definition: time.c:37
BOOLEAN DosControlBreak(VOID)
Definition: dos.c:181
static BOOLEAN DosIsFileOnCdRom(VOID)
Definition: dos.c:164
static BOOLEAN DosChangeDirectory(LPSTR Directory)
Definition: dos.c:78
VOID WINAPI DosInt21h(LPWORD Stack)
Definition: dos.c:210
static BOOLEAN DosChangeDrive(BYTE Drive)
Definition: dos.c:52
WORD DosReadFile(WORD FileHandle, DWORD Buffer, WORD Count, LPWORD BytesRead)
Definition: dosfiles.c:768
PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle)
Definition: dosfiles.c:173
WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes)
Definition: dosfiles.c:521
WORD DosCreateFileEx(LPWORD Handle, LPWORD CreationStatus, LPCSTR FilePath, BYTE AccessShareModes, WORD CreateActionFlags, WORD Attributes)
Definition: dosfiles.c:181
WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, DWORD CreationDisposition, WORD Attributes)
Definition: dosfiles.c:442
BYTE DosReadLineBuffered(WORD FileHandle, DWORD Buffer, BYTE MaxSize)
Definition: dosfiles.c:674
BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size)
Definition: dosfiles.c:1105
BOOL DosFlushFileBuffers(WORD FileHandle)
Definition: dosfiles.c:1056
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
Definition: dosfiles.c:1001
BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size)
Definition: dosfiles.c:1082
WORD DosWriteFile(WORD FileHandle, DWORD Buffer, WORD Count, LPWORD BytesWritten)
Definition: dosfiles.c:915
BOOLEAN DosDeviceIoControl(WORD FileHandle, BYTE ControlCode, DWORD Buffer, PWORD Length)
Definition: dosfiles.c:1185
#define FILE_INFO_DEVICE
Definition: dosfiles.h:16
#define FAR_POINTER(x)
Definition: emulator.h:35
#define SEG_OFF_TO_PTR(seg, off)
Definition: emulator.h:32
@ Success
Definition: eventcreate.c:712
UINT WINAPI GetTempFileNameA(IN LPCSTR lpPathName, IN LPCSTR lpPrefixString, IN UINT uUnique, OUT LPSTR lpTempFileName)
Definition: filename.c:26
unsigned short WORD
Definition: ntddk_ex.h:93
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define LOBYTE(W)
Definition: jmemdos.c:487
#define PCHAR
Definition: match.c:90
#define CREATE_ALWAYS
Definition: disk.h:72
#define CREATE_NEW
Definition: disk.h:69
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define DPRINT
Definition: sndvol32.h:71
Definition: dos.h:54
WORD DosVersion
Definition: process.h:43
Definition: dos.h:149
WORD ErrorLevel
Definition: dos.h:167
BYTE AllocStrategy
Definition: dos.h:152
DWORD DiskTransferArea
Definition: dos.h:164
BYTE ErrorMode
Definition: dos.h:156
BYTE InDos
Definition: dos.h:157
DWORD FirstDpb
Definition: dos.h:80
BYTE BootDrive
Definition: dos.h:96
BYTE UmbLinked
Definition: dos.h:100
WORD wYear
Definition: winbase.h:905
WORD wMilliseconds
Definition: winbase.h:912
WORD wMonth
Definition: winbase.h:906
WORD wHour
Definition: winbase.h:909
WORD wSecond
Definition: winbase.h:911
WORD wMinute
Definition: winbase.h:910
WORD wDay
Definition: winbase.h:908
WORD wDayOfWeek
Definition: winbase.h:907
#define EMULATOR_FLAG_ZF
Definition: cpu.h:22
CHAR DosReadCharacter(WORD FileHandle, BOOLEAN Echo)
Definition: bios.c:85
BOOLEAN DosCheckInput(VOID)
Definition: bios.c:120
#define NTDOS_VERSION
Definition: dos.h:25
#define INVALID_DOS_HANDLE
Definition: dos.h:41
struct _DOS_FCB * PDOS_FCB
#define DOS_DATA_OFFSET(x)
Definition: dos.h:35
#define DOS_INPUT_HANDLE
Definition: dos.h:42
struct _DOS_INPUT_BUFFER * PDOS_INPUT_BUFFER
#define DOS_DATA_SEGMENT
Definition: dos.h:33
WORD DosDuplicateHandle(WORD DosHandle)
Definition: handle.c:256
BOOLEAN DosCloseHandle(WORD DosHandle)
Definition: handle.c:311
BOOLEAN DosResizeHandleTable(WORD NewSize)
Definition: handle.c:118
BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle)
Definition: handle.c:269
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
Definition: memory.c:289
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
Definition: memory.c:136
BOOLEAN DosUnlinkUmb(VOID)
Definition: memory.c:492
BOOLEAN DosLinkUmb(VOID)
Definition: memory.c:446
BOOLEAN DosFreeMemory(WORD BlockData)
Definition: memory.c:418
#define DOS_ALLOC_HIGH_LOW
Definition: memory.h:18
#define DOS_ALLOC_HIGH
Definition: memory.h:17
@ DOS_ALLOC_LAST_FIT
Definition: memory.h:24
VOID DosClonePsp(WORD DestSegment, WORD SourceSegment)
Definition: process.c:251
VOID DosCreatePsp(WORD Segment, WORD ProgramSize)
Definition: process.c:278
DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType, IN LPCSTR ExecutablePath, IN PDOS_EXEC_PARAM_BLOCK Parameters, IN LPCSTR CommandLine OPTIONAL, IN LPCSTR Environment OPTIONAL, IN DWORD ReturnAddress OPTIONAL)
Definition: process.c:705
WORD DosCreateProcess(IN LPCSTR ProgramName, IN PDOS_EXEC_PARAM_BLOCK Parameters, IN DWORD ReturnAddress OPTIONAL)
Definition: process.c:793
VOID DosSetProcessContext(WORD Segment)
Definition: process.c:329
#define SEGMENT_TO_PSP(seg)
Definition: process.h:16
DOS_EXEC_TYPE
Definition: process.h:19
@ DOS_LOAD_OVERLAY
Definition: process.h:22
@ DOS_LOAD_AND_EXECUTE
Definition: process.h:20
uint32_t * PULONG
Definition: typedefs.h:59
char * PSTR
Definition: typedefs.h:51
#define MAKEWORD(a, b)
Definition: typedefs.h:248
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define MAKELONG(a, b)
Definition: typedefs.h:249
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
char * PCHAR
Definition: typedefs.h:51
VOID WINAPI setCX(USHORT)
Definition: registers.c:235
VOID WINAPI setDX(USHORT)
Definition: registers.c:293
VOID WINAPI setAL(UCHAR)
Definition: registers.c:149
UCHAR WINAPI getCH(VOID)
Definition: registers.c:242
VOID WINAPI setDL(UCHAR)
Definition: registers.c:321
USHORT WINAPI getDS(VOID)
Definition: registers.c:508
UCHAR WINAPI getAL(VOID)
Definition: registers.c:142
USHORT WINAPI getCX(VOID)
Definition: registers.c:228
USHORT WINAPI getSI(VOID)
Definition: registers.c:404
USHORT WINAPI getDX(VOID)
Definition: registers.c:286
VOID WINAPI setDS(USHORT)
Definition: registers.c:515
UCHAR WINAPI getCL(VOID)
Definition: registers.c:256
USHORT WINAPI getES(VOID)
Definition: registers.c:522
VOID WINAPI setDH(UCHAR)
Definition: registers.c:307
USHORT WINAPI getDI(VOID)
Definition: registers.c:434
UCHAR WINAPI getDL(VOID)
Definition: registers.c:314
UCHAR WINAPI getBL(VOID)
Definition: registers.c:198
VOID WINAPI setES(USHORT)
Definition: registers.c:529
UCHAR WINAPI getAH(VOID)
Definition: registers.c:128
VOID WINAPI setSI(USHORT)
Definition: registers.c:411
USHORT WINAPI getSS(VOID)
Definition: registers.c:494
UCHAR WINAPI getDH(VOID)
Definition: registers.c:300
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3534
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2433
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR InputBuffer
Definition: wdfiotarget.h:953
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
#define ERROR_NOT_READY
Definition: winerror.h:124
#define ERROR_INVALID_DRIVE
Definition: winerror.h:118
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
const char * LPCSTR
Definition: xmlstorage.h:183

Referenced by DosInt21h(), and DosKRNLInitialize().

◆ DosInt27h()

VOID WINAPI DosInt27h ( LPWORD  Stack)

Definition at line 2072 of file dos.c.

2073{
2074 WORD KeepResident = (getDX() + 0x0F) >> 4;
2075
2076 /* Terminate and Stay Resident. CS must be the PSP segment. */
2077 DPRINT1("Process going resident: %u paragraphs kept\n", KeepResident);
2078 DosTerminateProcess(Stack[STACK_CS], 0, KeepResident);
2079}

Referenced by DosKRNLInitialize().

◆ DosInt2Ah()

VOID WINAPI DosInt2Ah ( LPWORD  Stack)

Definition at line 2122 of file dos.c.

2123{
2124 DPRINT1("INT 2Ah, AX=%4xh called\n", getAX());
2125}

Referenced by DosKRNLInitialize().

◆ DosInt2Fh()

VOID WINAPI DosInt2Fh ( LPWORD  Stack)

Definition at line 2127 of file dos.c.

2128{
2129 switch (getAH())
2130 {
2131 /* DOS 3+ Internal Utility Functions */
2132 case 0x12:
2133 {
2134 DPRINT1("INT 2Fh, AX=%4xh DOS Internal Utility Function called\n", getAX());
2135
2136 switch (getAL())
2137 {
2138 /* Installation Check */
2139 case 0x00:
2140 {
2141 setAL(0xFF);
2142 break;
2143 }
2144
2145 /* Get DOS Data Segment */
2146 case 0x03:
2147 {
2149 break;
2150 }
2151
2152 /* Compare FAR Pointers */
2153 case 0x14:
2154 {
2155 PVOID PointerFromFarPointer1 = SEG_OFF_TO_PTR(getDS(), getSI());
2156 PVOID PointerFromFarPointer2 = SEG_OFF_TO_PTR(getES(), getDI());
2157 BOOLEAN AreEqual = (PointerFromFarPointer1 == PointerFromFarPointer2);
2158
2159 if (AreEqual)
2160 {
2162 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
2163 }
2164 else
2165 {
2166 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
2168 }
2169 break;
2170 }
2171
2172 /* Set DOS Version Number to return */
2173 case 0x2F:
2174 {
2175 WORD DosVersion = getDX();
2176
2177 // Special case: return the true DOS version when DX=00h
2178 if (DosVersion == 0x0000)
2180 else
2181 DosData->DosVersion = DosVersion;
2182
2183 break;
2184 }
2185 }
2186
2187 break;
2188 }
2189
2190 /* Set Disk Interrupt Handler */
2191 case 0x13:
2192 {
2193 /* Save the old values of PrevInt13 and RomBiosInt13 */
2194 ULONG OldInt13 = BiosData->PrevInt13;
2195 ULONG OldBiosInt13 = BiosData->RomBiosInt13;
2196
2197 /* Set PrevInt13 and RomBiosInt13 to their new values */
2200
2201 /* Return in DS:DX the old value of PrevInt13 */
2202 setDS(HIWORD(OldInt13));
2203 setDX(LOWORD(OldInt13));
2204
2205 /* Return in DS:DX the old value of RomBiosInt13 */
2206 setES(HIWORD(OldBiosInt13));
2207 setBX(LOWORD(OldBiosInt13));
2208
2209 break;
2210 }
2211
2212 /* Mostly Windows 2.x/3.x/9x support */
2213 case 0x16:
2214 {
2215 /*
2216 * AL=80h is DOS/Windows/DPMI "Release Current Virtual Machine Time-slice"
2217 * Just do nothing in this case.
2218 */
2219 if (getAL() != 0x80) goto Default;
2220 break;
2221 }
2222
2223 /* Extended Memory Specification */
2224 case 0x43:
2225 {
2227 if (!XmsGetDriverEntry(&DriverEntry)) break;
2228
2229 switch (getAL())
2230 {
2231 /* Installation Check */
2232 case 0x00:
2233 {
2234 /* The driver is loaded */
2235 setAL(0x80);
2236 break;
2237 }
2238
2239 /* Get Driver Address */
2240 case 0x10:
2241 {
2244 break;
2245 }
2246
2247 default:
2248 DPRINT1("Unknown DOS XMS Function: INT 2Fh, AH = 43h, AL = %02Xh\n", getAL());
2249 break;
2250 }
2251
2252 break;
2253 }
2254
2255 default: Default:
2256 {
2257 DPRINT1("DOS Internal System Function INT 2Fh, AH = %02Xh, AL = %02Xh NOT IMPLEMENTED!\n",
2258 getAH(), getAL());
2260 }
2261 }
2262}
DRIVER_INITIALIZE DriverEntry
Definition: condrv.c:21
BOOLEAN XmsGetDriverEntry(PDWORD Pointer)
Definition: himem.c:789
@ Default
Definition: stdole2.idl:392
DWORD PrevInt13
Definition: dos.h:296
DWORD RomBiosInt13
Definition: dos.h:295
WORD DosVersion
Definition: dos.h:255
PBIOS_DATA BiosData
Definition: bios.c:42
#define DOS_VERSION
Definition: dos.h:24

Referenced by DosKRNLInitialize().

◆ DosIsFileOnCdRom()

static BOOLEAN DosIsFileOnCdRom ( VOID  )
static

Definition at line 164 of file dos.c.

165{
167 CHAR RootPathName[4];
168
169 /* Construct a simple <letter>:\ string to get drive type */
170 RootPathName[0] = Sda->CurrentDrive + 'A';
171 RootPathName[1] = ':';
172 RootPathName[2] = '\\';
173 RootPathName[3] = ANSI_NULL;
174
175 DriveType = GetDriveTypeA(RootPathName);
176 return (DriveType == DRIVE_CDROM);
177}
UINT DriveType
UINT WINAPI GetDriveTypeA(IN LPCSTR lpRootPathName)
Definition: disk.c:468
#define DRIVE_CDROM
Definition: machpc98.h:119
#define ANSI_NULL

Referenced by DosInt21h().

◆ DosKRNLInitialize()

BOOLEAN DosKRNLInitialize ( VOID  )

Definition at line 2264 of file dos.c.

2265{
2266 UCHAR i;
2267 PDOS_SFT Sft;
2268 LPSTR Path;
2270 DWORD dwRet;
2272 CHAR DosDirectory[DOS_DIR_LENGTH];
2273
2274 static const BYTE NullDriverRoutine[] =
2275 {
2276 /* Strategy routine entry */
2277 0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
2278 0xC7,
2279 0x47,
2283
2284 /* Interrupt routine entry */
2285 0xCB, // retf
2286 };
2287
2288 /* Set the data segment */
2290
2291 /* Initialize the global DOS data area */
2293 RtlZeroMemory(DosData, sizeof(*DosData));
2294
2295 /* Initialize the DOS stack */
2297 setSP(DOS_DATA_OFFSET(DosStack) + sizeof(DosData->DosStack) - sizeof(WORD));
2298
2299 /* Initialize the list of lists */
2301 RtlZeroMemory(SysVars, sizeof(*SysVars));
2303 SysVars->CurrentDirs = MAKELONG(DOS_DATA_OFFSET(CurrentDirectories),
2305 /*
2306 * The last drive can be redefined with the LASTDRIVE command.
2307 * At the moment, set the real maximum possible, 'Z'.
2308 */
2309 SysVars->NumLocalDrives = 'Z' - 'A' + 1; // See #define NUM_DRIVES in dos.h
2310
2311 /* The boot drive is initialized to the %SYSTEMDRIVE% value */
2312 // NOTE: Using the NtSystemRoot system variable might be OS-specific...
2313 SysVars->BootDrive = RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]) - 'A' + 1;
2314
2315 /* Initialize the NUL device driver */
2318 // Offset from within the DOS data segment
2319 SysVars->NullDevice.StrategyRoutine = DOS_DATA_OFFSET(NullDriverRoutine);
2320 // Hardcoded to the RETF inside StrategyRoutine
2323 sizeof(SysVars->NullDevice.DeviceName),
2324 ' ');
2327 NullDriverRoutine,
2328 sizeof(NullDriverRoutine));
2329
2330 /* Default DOS version to report */
2332
2333 /* Initialize the swappable data area */
2334 Sda = &DosData->Sda;
2335 RtlZeroMemory(Sda, sizeof(*Sda));
2336
2337 /* Get the current directory and convert it to a DOS path */
2339 if (dwRet == 0)
2340 {
2341 Success = FALSE;
2342 DPRINT1("GetCurrentDirectoryA failed (Error: %u)\n", GetLastError());
2343 }
2344 else if (dwRet > sizeof(CurrentDirectory))
2345 {
2346 Success = FALSE;
2347 DPRINT1("Current directory too long (%d > MAX_PATH) for GetCurrentDirectoryA\n", dwRet);
2348 }
2349
2350 if (Success)
2351 {
2352 dwRet = GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory));
2353 if (dwRet == 0)
2354 {
2355 Success = FALSE;
2356 DPRINT1("GetShortPathNameA failed (Error: %u)\n", GetLastError());
2357 }
2358 else if (dwRet > sizeof(DosDirectory))
2359 {
2360 Success = FALSE;
2361 DPRINT1("Short path too long (%d > DOS_DIR_LENGTH) for GetShortPathNameA\n", dwRet);
2362 }
2363 }
2364
2365 if (!Success)
2366 {
2367 /* We failed, use the boot drive instead */
2368 DosDirectory[0] = SysVars->BootDrive + 'A' - 1;
2369 DosDirectory[1] = ':';
2370 DosDirectory[2] = '\\';
2371 DosDirectory[3] = '\0';
2372 }
2373
2374 /* Set the current drive */
2375 Sda->CurrentDrive = RtlUpperChar(DosDirectory[0]) - 'A';
2376
2377 /* Get the directory part of the path and set the current directory */
2378 Path = strchr(DosDirectory, '\\');
2379 if (Path != NULL)
2380 {
2381 Path++; // Skip the backslash
2383 }
2384 else
2385 {
2387 }
2388
2389 /* Set the current PSP to the system PSP */
2391
2392 /* Initialize the SFT */
2394 Sft->Link = MAXDWORD;
2396
2397 for (i = 0; i < Sft->NumDescriptors; i++)
2398 {
2399 /* Clear the file descriptor entry */
2401 }
2402
2403 /* Initialize memory management */
2405
2406 /* Initialize the callback context */
2408
2409 /* Register the DOS 32-bit Interrupts */
2412// RegisterDosInt32(0x22, DosInt22h ); // Termination
2413 RegisterDosInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break
2414// RegisterDosInt32(0x24, DosInt24h ); // Critical Error
2415 RegisterDosInt32(0x25, DosAbsoluteRead ); // Absolute Disk Read
2416 RegisterDosInt32(0x26, DosAbsoluteWrite ); // Absolute Disk Write
2417 RegisterDosInt32(0x27, DosInt27h ); // Terminate and Stay Resident
2418 RegisterDosInt32(0x28, DosIdle ); // DOS Idle Interrupt
2419 RegisterDosInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output
2420 RegisterDosInt32(0x2F, DosInt2Fh ); // Multiplex Interrupt
2421
2422 /* Unimplemented DOS interrupts */
2423 RegisterDosInt32(0x2A, DosInt2Ah); // DOS Critical Sections / Network
2424// RegisterDosInt32(0x2E, NULL); // COMMAND.COM "Reload Transient"
2425// COMMAND.COM adds support for INT 2Fh, AX=AE00h and AE01h "Installable Command - Installation Check & Execute"
2426// COMMAND.COM adds support for INT 2Fh, AX=5500h "COMMAND.COM Interface"
2427
2428 /* Reserved DOS interrupts */
2429 RegisterDosInt32(0x2B, NULL);
2430 RegisterDosInt32(0x2C, NULL);
2431 RegisterDosInt32(0x2D, NULL);
2432
2433 /* Initialize country data */
2435
2436 /* Load the CON driver */
2438
2439 /* Load the XMS driver (HIMEM) */
2440 XmsInitialize();
2441
2442 /* Load the EMS driver */
2444 {
2445 DosDisplayMessage("Could not initialize EMS. EMS will not be available.\n"
2446 "Page frame segment or number of EMS pages invalid.\n");
2447 }
2448
2449 /* Finally initialize the UMBs */
2451
2452 return TRUE;
2453}
BOOLEAN DosCountryInitialize(VOID)
Definition: country.c:236
#define DosDisplayMessage(Format,...)
Definition: dem.h:38
VOID WINAPI DosAbsoluteWrite(LPWORD Stack)
Definition: dos.c:2052
VOID WINAPI DosIdle(LPWORD Stack)
Definition: dos.c:2081
VOID WINAPI DosBreakInterrupt(LPWORD Stack)
Definition: dos.c:2026
VOID WINAPI DosInt27h(LPWORD Stack)
Definition: dos.c:2072
VOID WINAPI DosFastConOut(LPWORD Stack)
Definition: dos.c:2090
VOID WINAPI DosInt20h(LPWORD Stack)
Definition: dos.c:201
VOID WINAPI DosInt2Fh(LPWORD Stack)
Definition: dos.c:2127
VOID WINAPI DosAbsoluteRead(LPWORD Stack)
Definition: dos.c:2032
VOID WINAPI DosInt2Ah(LPWORD Stack)
Definition: dos.c:2122
struct _DOS_SFT * PDOS_SFT
BOOLEAN EmsDrvInitialize(USHORT Segment, ULONG TotalPages)
Definition: emsdrv.c:767
#define EMS_TOTAL_PAGES
Definition: emsdrv.h:24
#define EMS_SEGMENT
Definition: emsdrv.h:16
Status
Definition: gdiplustypes.h:25
VOID XmsInitialize(VOID)
Definition: himem.c:796
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
#define HIBYTE(W)
Definition: jmemdos.c:486
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:176
#define MAXDWORD
#define SharedUserData
DOS_SYSVARS SysVars
Definition: dos.h:253
DOS_SDA Sda
Definition: dos.h:256
BYTE DosStack[384]
Definition: dos.h:259
BYTE NullDriverRoutine[7]
Definition: dos.h:254
DWORD Link
Definition: device.h:110
WORD StrategyRoutine
Definition: device.h:112
WORD DeviceAttributes
Definition: device.h:111
WORD InterruptRoutine
Definition: device.h:113
CHAR DeviceName[MAX_DEVICE_NAME]
Definition: device.h:117
WORD NumDescriptors
Definition: dosfiles.h:67
DOS_FILE_DESCRIPTOR FileDescriptors[ANYSIZE_ARRAY]
Definition: dosfiles.h:68
DWORD Link
Definition: dosfiles.h:66
DWORD CurrentDirs
Definition: dos.h:85
DWORD FirstSft
Definition: dos.h:81
DOS_DRIVER NullDevice
Definition: dos.h:89
VOID InitializeContext(IN PCALLBACK16 Context, IN USHORT Segment, IN USHORT Offset)
Definition: callback.c:60
VOID ConDrvInitialize(VOID)
Definition: condrv.c:132
#define DOS_DEVATTR_NUL
Definition: device.h:23
#define DOS_DEVSTAT_DONE
Definition: device.h:49
#define DOS_DEVATTR_CHARACTER
Definition: device.h:29
struct _DOS_DATA * PDOS_DATA
#define DOS_CODE_SEGMENT
Definition: dos.h:32
#define SYSTEM_PSP
Definition: dos.h:39
#define DOS_SFT_SIZE
Definition: dos.h:46
#define RegisterDosInt32(IntNumber, IntHandler)
Definition: dos.h:314
VOID DosInitializeUmb(VOID)
Definition: memory.c:582
VOID DosInitializeMemory(VOID)
Definition: memory.c:665
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
VOID WINAPI setSS(USHORT)
Definition: registers.c:501
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by DosBIOSInitialize().

Variable Documentation

◆ DosContext

◆ DosData

◆ Sda

◆ SysVars