aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Serpell <daniel.serpell@gmail.com>2020-05-11 20:13:11 -0400
committerDaniel Serpell <daniel.serpell@gmail.com>2020-05-11 20:52:13 -0400
commitef46cac9c795acf9511c2337fc329f23fa2f057c (patch)
tree04cbbe697d109b8650dc378687386a8436217e84
parent8627d7ded3e995464b940501c60dcd5bf34e76d4 (diff)
downloademu2-ef46cac9c795acf9511c2337fc329f23fa2f057c.tar.gz
Minimal support for child processes.
Implements DOS functions 50h, 51h, 55h and expands 4Ch, adds a handler for int-22 that terminates the emulator. With this the in memory debugger in Turbo Pascal 5.5 works.
-rw-r--r--src/dos.c96
-rw-r--r--src/dos.h1
-rw-r--r--src/loader.c19
-rw-r--r--src/loader.h1
-rw-r--r--src/main.c2
5 files changed, 104 insertions, 15 deletions
diff --git a/src/dos.c b/src/dos.c
index 4ac59ec..203eff0 100644
--- a/src/dos.c
+++ b/src/dos.c
@@ -892,7 +892,7 @@ static void int21_debug(void)
ax, fn, cpuGetBX(), cpuGetCX(), cpuGetDX(), cpuGetDI(), cpuGetDS(), cpuGetES());
}
-// DOS int
+// DOS int 21
void int21()
{
// Check CP/M call, INT 21h from address 0x000C0
@@ -918,8 +918,19 @@ void int21()
debug(debug_int, "D-21%04X: BX=%04X\n", cpuGetAX(), cpuGetBX());
if(debug_active(debug_dos))
int21_debug();
- unsigned ax = cpuGetAX();
- switch(ax >> 8)
+
+ // Process interrupt
+ unsigned ax = cpuGetAX(), ah = ax >> 8;
+
+ // Store SS:SP into PSP, used at return from child process
+ // According to DOSBOX, only set for certain functions:
+ if(ah != 0x50 && ah != 0x51 && ah != 0x62 && ah != 0x64 && ah < 0x6c)
+ {
+ put16(cpuGetAddress(get_current_PSP(), 0x2E), cpuGetSP());
+ put16(cpuGetAddress(get_current_PSP(), 0x30), cpuGetSS());
+ }
+
+ switch(ah)
{
case 0: // TERMINATE PROGRAM
exit(0);
@@ -1070,22 +1081,17 @@ void int21()
put16(4 * (ax & 0xFF), cpuGetDX());
put16(4 * (ax & 0xFF) + 2, cpuGetDS());
break;
- case 0x26: // Create PSP (allocate segment (singleton), and copy PSP)
+ case 0x26: // Create PSP (duplicate current PSP)
{
- uint8_t *new_base = getptr(cpuGetAddress(cpuGetDX(), 0), 0x100);
- uint8_t *orig = getptr(cpuGetAddress(get_current_PSP(), 0), 0x100);
- if(!new_base || !orig)
+ uint8_t *new_psp = getptr(cpuGetAddress(cpuGetDX(), 0), 0x100);
+ uint8_t *orig_psp = getptr(cpuGetAddress(get_current_PSP(), 0), 0x100);
+ if(!new_psp || !orig_psp)
{
debug(debug_dos, "\tinvalid new PSP segment %04x.\n", cpuGetDX());
break;
}
// Copy PSP to the new segment, 0x80 is what DOS does - this excludes command line
- memcpy(new_base, orig, 0x80);
- debug(debug_dos, "\tnew PSP segment %04x.\n", cpuGetDX());
- debug(debug_dos, "\tnew PSP size %02x%02x.\n", new_base[7], new_base[6]);
- debug(debug_dos, "\toriginal PSP segment %04x.\n", get_current_PSP());
- debug(debug_dos, "\toriginal PSP size %02x%02x.\n", orig[7], orig[6]);
- // TODO: Initialize PSP values: int 22h, 23h, 24h and parent PSP segment to 0
+ memcpy(new_psp, orig_psp, 0x80);
break;
}
case 0x27: // BLOCK READ FROM FCB
@@ -1672,7 +1678,37 @@ void int21()
break;
}
case 0x4C: // EXIT
- exit(ax & 0xFF);
+ // Detect if our PSP is last one
+ debug(debug_dos, "\texit PSP:'%04x', PARENT:%04x.\n", get_current_PSP(),
+ get16(cpuGetAddress(get_current_PSP(), 22)));
+ if(0xFFFE == get16(cpuGetAddress(get_current_PSP(), 22)))
+ exit(ax & 0xFF);
+ else
+ {
+ // Exit to parent
+ // TODO: we must close all child file descriptors and dealocate
+ // child memory.
+ return_code = cpuGetAX() & 0xFF;
+ // Patch INT 22h, 23h and 24h addresses to the ones saved in new PSP
+ put16(0x88, get16(cpuGetAddress(get_current_PSP(), 10)));
+ put16(0x8A, get16(cpuGetAddress(get_current_PSP(), 12)));
+ put16(0x8C, get16(cpuGetAddress(get_current_PSP(), 14)));
+ put16(0x8E, get16(cpuGetAddress(get_current_PSP(), 16)));
+ put16(0x90, get16(cpuGetAddress(get_current_PSP(), 18)));
+ put16(0x92, get16(cpuGetAddress(get_current_PSP(), 20)));
+ // Set PSP to parent
+ set_current_PSP(get16(cpuGetAddress(get_current_PSP(), 22)));
+ // Get last stack
+ cpuSetSS(get16(cpuGetAddress(get_current_PSP(), 0x30)));
+ cpuSetSP(get16(cpuGetAddress(get_current_PSP(), 0x2E)));
+ int stack = cpuGetAddress(cpuGetSS(), cpuGetSP());
+ // Fixup interrupt return
+ put16(stack, get16(0x22 * 4));
+ put16(stack + 2, get16(0x22 * 4 + 2));
+ put16(stack + 4, 0xf202);
+ // And exit!
+ }
+ break;
case 0x4D: // GET RETURN CODE (ERRORLEVEL)
cpuSetAX(return_code);
return_code = 0;
@@ -1684,11 +1720,33 @@ void int21()
case 0x4F: // FIND NEXT MATCHING FILE
dos_find_next(0);
break;
+ case 0x50: // SET CURRENT PSP
+ set_current_PSP(cpuGetBX());
+ break;
+ case 0x51: // GET CURRENT PSP
+ cpuSetBX(get_current_PSP());
+ break;
case 0x52: // GET SYSVARS
cpuSetES(dos_sysvars >> 4);
cpuSetBX((dos_sysvars & 0xF) + 24);
- cpuClrFlag(cpuFlag_CF);
break;
+ case 0x55: // Create CHILD PSP
+ {
+ uint8_t *new_psp = getptr(cpuGetAddress(cpuGetDX(), 0), 0x100);
+ uint8_t *orig_psp = getptr(cpuGetAddress(get_current_PSP(), 0), 0x100);
+ if(!new_psp || !orig_psp)
+ {
+ debug(debug_dos, "\tinvalid new PSP segment %04x.\n", cpuGetDX());
+ break;
+ }
+ // Copy PSP to the new segment, 0x80 is what DOS does - this excludes command line
+ memcpy(new_psp, orig_psp, 0x80);
+ // Set parent PSP to the current one
+ new_psp[22] = get_current_PSP() & 0xFF;
+ new_psp[23] = get_current_PSP() >> 8;
+ set_current_PSP(cpuGetDX());
+ break;
+ }
case 0x56: // RENAME
{
char *fname1 = dos_unix_path(cpuGetAddrDS(cpuGetDX()), 0);
@@ -1806,6 +1864,14 @@ void int21()
}
}
+// DOS int 22 - TERMINATE ADDRESS
+void int22()
+{
+ debug(debug_dos, "D-22: TERMINATE HANDLER CALLED\n");
+ // If we reached here, we must terminate now
+ exit(return_code & 0xFF);
+}
+
static char *addstr(char *dst, const char *src, int limit)
{
while(limit > 0 && *src)
diff --git a/src/dos.h b/src/dos.h
index 0ead371..412f580 100644
--- a/src/dos.h
+++ b/src/dos.h
@@ -6,4 +6,5 @@
void init_dos(int argc, char **argv);
void int20(void);
void int21(void);
+void int22(void);
void int28(void);
diff --git a/src/loader.c b/src/loader.c
index 1d8225f..7c6c839 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -666,6 +666,20 @@ uint16_t create_PSP(const char *cmdline, const char *environment, int env_size,
dosPSP[7] = 0xFE; // this jumps to 0xC0, where an
dosPSP[8] = 0x1D; // INT 21h is patched.
dosPSP[9] = 0xF0;
+ dosPSP[10] = 0x22; // Handler for INT 22h
+ dosPSP[11] = 0x00;
+ dosPSP[12] = 0x00;
+ dosPSP[13] = 0x00;
+ dosPSP[14] = 0x23; // Handler for INT 23h
+ dosPSP[15] = 0x00;
+ dosPSP[16] = 0x00;
+ dosPSP[17] = 0x00;
+ dosPSP[18] = 0x24; // Handler for INT 24h
+ dosPSP[19] = 0x00;
+ dosPSP[20] = 0x00;
+ dosPSP[21] = 0x00;
+ dosPSP[22] = 0xFE; // 16: Parent PSP, use special value of FFFE
+ dosPSP[23] = 0xFF; // to signal no parent DOS process
dosPSP[44] = 0xFF & env_seg; // 2C: environment segment
dosPSP[45] = 0xFF & (env_seg >> 8); //
dosPSP[80] = 0xCD; // 50: INT 21h / RETF
@@ -698,6 +712,11 @@ unsigned get_current_PSP(void)
return current_PSP;
}
+void set_current_PSP(unsigned psp_seg)
+{
+ current_PSP = psp_seg;
+}
+
static int g16(uint8_t *buf)
{
return buf[0] + (buf[1] << 8);
diff --git a/src/loader.h b/src/loader.h
index 6f5bfa1..b44f414 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -7,6 +7,7 @@
uint16_t create_PSP(const char *cmdline, const char *environment, int env_size,
const char *progname);
unsigned get_current_PSP(void);
+void set_current_PSP(unsigned psp_seg);
// DOS Memory handling
int mem_resize_segment(int seg, int size);
diff --git a/src/main.c b/src/main.c
index 9bc5b09..d0c0d2f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -84,6 +84,8 @@ void bios_routine(unsigned inum)
int21();
else if(inum == 0x20)
int20();
+ else if(inum == 0x22)
+ int22();
else if(inum == 0x1A)
int1A();
else if(inum == 0x19)
Un proyecto texto-plano.xyz