Subversion Repositories SvarDOS

Rev

Rev 1591 | Rev 1595 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1591 Rev 1594
1
/* This file is part of the SvarCOM project and is published under the terms
1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
2
 * of the MIT license.
3
 *
3
 *
4
 * Copyright (C) 2021-2022 Mateusz Viste
4
 * Copyright (C) 2021-2022 Mateusz Viste
5
 *
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
12
 *
13
 * The above copyright notice and this permission notice shall be included in
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
14
 * all copies or substantial portions of the Software.
15
 *
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
22
 * DEALINGS IN THE SOFTWARE.
23
 */
23
 */
24
 
24
 
25
#include <i86.h>
25
#include <i86.h>
26
#include <string.h>
26
#include <string.h>
27
 
27
 
28
#include "env.h"
28
#include "env.h"
29
#include "helpers.h"
29
#include "helpers.h"
30
 
30
 
31
#include "rmodinit.h"
31
#include "rmodinit.h"
32
 
32
 
33
 
33
 
34
/* returns far pointer to rmod's settings block on success */
34
/* returns far pointer to rmod's settings block on success */
35
struct rmod_props far *rmod_install(unsigned short envsize, unsigned char *rmodcore, unsigned short rmodcore_len) {
35
struct rmod_props far *rmod_install(unsigned short envsize, unsigned char *rmodcore, unsigned short rmodcore_len) {
36
  char far *myptr, far *mcb;
36
  char far *myptr, far *mcb;
37
  unsigned short far *owner;
37
  unsigned short far *owner;
38
  const unsigned short sizeof_rmodandprops_paras = (0x100 + rmodcore_len + sizeof(struct rmod_props) + 15) / 16;
38
  const unsigned short sizeof_rmodandprops_paras = (0x100 + rmodcore_len + sizeof(struct rmod_props) + 15) / 16;
39
  unsigned short rmodseg = 0xffff;
39
  unsigned short rmodseg = 0xffff;
40
  unsigned short envseg, origenvseg;
40
  unsigned short envseg, origenvseg;
41
  struct rmod_props far *res;
41
  struct rmod_props far *res;
42
 
42
 
43
  /* read my current env segment from PSP and save it */
43
  /* read my current env segment from PSP and save it */
44
  envseg = *((unsigned short *)0x2c);
44
  envseg = *((unsigned short *)0x2c);
45
  origenvseg = envseg;
45
  origenvseg = envseg;
46
 
46
 
47
  /* printf("original (PSP) env buffer at %04X\r\n", envseg); */
47
  /* printf("original (PSP) env buffer at %04X\r\n", envseg); */
48
 
48
 
49
  /* if envseg is zero, then enforce our own one (MSDOS 5 does not provide a default env) */
49
  /* if envseg is zero, then enforce our own one (MSDOS 5 does not provide a default env) */
50
  if ((envseg == 0) && (envsize == 0)) envsize = 256;
50
  if ((envseg == 0) && (envsize == 0)) envsize = 256;
51
 
51
 
52
  /* if custom envsize requested, convert it to number of paragraphs */
52
  /* if custom envsize requested, convert it to number of paragraphs */
53
  if (envsize != 0) {
53
  if (envsize != 0) {
54
    envsize += 15;
54
    envsize += 15;
55
    envsize /= 16;
55
    envsize /= 16;
56
  }
56
  }
57
 
57
 
58
  _asm {
58
  _asm {
-
 
59
    push bx
-
 
60
    push cx
-
 
61
    push dx
-
 
62
 
59
    /* link in the UMB memory chain for enabling high-memory allocation (and save initial status on stack) */
63
    /* link in the UMB memory chain for enabling high-memory allocation (and save initial status on stack) */
60
    mov ax, 0x5802  /* GET UMB LINK STATE */
64
    mov ax, 0x5802  /* GET UMB LINK STATE */
61
    int 0x21
65
    int 0x21
62
    xor ah, ah
66
    xor ah, ah
63
    push ax         /* save link state on stack */
67
    push ax         /* save link state on stack */
64
    mov ax, 0x5803  /* SET UMB LINK STATE */
68
    mov ax, 0x5803  /* SET UMB LINK STATE */
65
    mov bx, 1
69
    mov bx, 1
66
    int 0x21
70
    int 0x21
67
    /* get current allocation strategy and save it in DX */
71
    /* get current allocation strategy and save it in DX */
68
    mov ax, 0x5800
72
    mov ax, 0x5800
69
    int 0x21
73
    int 0x21
70
    push ax
74
    push ax
71
    pop dx
75
    pop dx
72
    /* set strategy to 'last fit, try high then low memory' */
76
    /* set strategy to 'last fit, try high then low memory' */
73
    mov ax, 0x5801
77
    mov ax, 0x5801
74
    mov bx, 0x0082
78
    mov bx, 0x0082
75
    int 0x21
79
    int 0x21
76
    /* ask for a memory block and save the given segment to rmodseg */
80
    /* ask for a memory block and save the given segment to rmodseg */
77
    mov ah, 0x48
81
    mov ah, 0x48
78
    mov bx, sizeof_rmodandprops_paras
82
    mov bx, sizeof_rmodandprops_paras
79
    int 0x21
83
    int 0x21
80
    jc ALLOC_FAIL
84
    jc ALLOC_FAIL
81
    mov rmodseg, ax
85
    mov rmodseg, ax
82
    /* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
86
    /* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
83
    mov bx, envsize
87
    mov bx, envsize
84
    test bx, bx
88
    test bx, bx
85
    jz ALLOC_FAIL
89
    jz ALLOC_FAIL
86
    mov ah, 0x48
90
    mov ah, 0x48
87
    int 0x21
91
    int 0x21
88
    jc ALLOC_FAIL
92
    jc ALLOC_FAIL
89
    mov envseg, ax
93
    mov envseg, ax
90
 
94
 
91
    ALLOC_FAIL:
95
    ALLOC_FAIL:
92
    /* restore initial allocation strategy */
96
    /* restore initial allocation strategy */
93
    mov ax, 0x5801
97
    mov ax, 0x5801
94
    mov bx, dx
98
    mov bx, dx
95
    int 0x21
99
    int 0x21
96
    /* restore initial UMB memory link state */
100
    /* restore initial UMB memory link state */
97
    mov ax, 0x5803
101
    mov ax, 0x5803
98
    pop bx       /* pop initial UMB link state from stack */
102
    pop bx       /* pop initial UMB link state from stack */
99
    int 0x21
103
    int 0x21
-
 
104
 
-
 
105
    pop dx
-
 
106
    pop cx
-
 
107
    pop bx
100
  }
108
  }
101
 
109
 
102
  if (rmodseg == 0xffff) {
110
  if (rmodseg == 0xffff) {
103
    outputnl("malloc error");
111
    outputnl("malloc error");
104
    return(NULL);
112
    return(NULL);
105
  }
113
  }
106
 
114
 
107
  /* generate a new PSP where RMOD is about to land */
115
  /* generate a new PSP where RMOD is about to land */
108
  _asm {
116
  _asm {
109
    push dx
117
    push dx
110
    mov ah, 0x26 /* CREATE NEW PROGRAM SEGMENT PREFIX (DOS 1+) */
118
    mov ah, 0x26 /* CREATE NEW PROGRAM SEGMENT PREFIX (DOS 1+) */
111
    mov dx, rmodseg
119
    mov dx, rmodseg
112
    int 0x21
120
    int 0x21
113
    pop dx
121
    pop dx
114
  }
122
  }
115
 
123
 
116
  myptr = MK_FP(rmodseg, 0);
124
  myptr = MK_FP(rmodseg, 0);
117
 
125
 
118
  /* patch up RMOD's PSP: Parent's PSP segment @ 0x16-0x17 */
126
  /* patch up RMOD's PSP: Parent's PSP segment @ 0x16-0x17 */
119
  myptr[0x16] = rmodseg & 0xff; /* RMOD is his own parent */
127
  myptr[0x16] = rmodseg & 0xff; /* RMOD is his own parent */
120
  myptr[0x17] = rmodseg >> 8;
128
  myptr[0x17] = rmodseg >> 8;
121
 
129
 
122
  /* patch up RMOD's PSP: SS:SP pointer @ 0x2E-0x31  --  I abuse the PSP's
130
  /* patch up RMOD's PSP: SS:SP pointer @ 0x2E-0x31  --  I abuse the PSP's
123
   * command line tail as stack, but I do NOT set the stack at the end of the
131
   * command line tail as stack, but I do NOT set the stack at the end of the
124
   * tail. E. C. Masloch kindly explained why this would be a bad idea:
132
   * tail. E. C. Masloch kindly explained why this would be a bad idea:
125
   *
133
   *
126
   * "This is wrong and will potentially overwrite part of your buffers that
134
   * "This is wrong and will potentially overwrite part of your buffers that
127
   * start past the PSP. This is because the dword [PSP:2Eh] is not used merely
135
   * start past the PSP. This is because the dword [PSP:2Eh] is not used merely
128
   * to set SS:SP but rather to find the stack frame created by the int 21h
136
   * to set SS:SP but rather to find the stack frame created by the int 21h
129
   * call. Therefore the int 21h call that terminates the child process will
137
   * call. Therefore the int 21h call that terminates the child process will
130
   * then pop a number of registers off starting from the address stored in the
138
   * then pop a number of registers off starting from the address stored in the
131
   * PSP." <https://github.com/SvarDOS/bugz/issues/38#issuecomment-1817445740>
139
   * PSP." <https://github.com/SvarDOS/bugz/issues/38#issuecomment-1817445740>
132
   */
140
   */
133
  myptr[0x2e] = 192; /* middle of the command line tail area so I have 64 bytes */
141
  myptr[0x2e] = 192; /* middle of the command line tail area so I have 64 bytes */
134
  myptr[0x2f] = 0;   /* before and 64 bytes in front of me */
142
  myptr[0x2f] = 0;   /* before and 64 bytes in front of me */
135
  myptr[0x30] = rmodseg & 0xff;
143
  myptr[0x30] = rmodseg & 0xff;
136
  myptr[0x31] = rmodseg >> 8;
144
  myptr[0x31] = rmodseg >> 8;
137
 
145
 
138
  /* patch up RMOD's PSP: JFT size @ 0x32-0x33 */
146
  /* patch up RMOD's PSP: JFT size @ 0x32-0x33 */
139
  myptr[0x32] = 20; /* default JFT size (max that fits without an extra allocation) */
147
  myptr[0x32] = 20; /* default JFT size (max that fits without an extra allocation) */
140
  myptr[0x33] = 0;
148
  myptr[0x33] = 0;
141
 
149
 
142
  /* patch up RMOD's PSP: JFT pointer @ 0x34-0x37 */
150
  /* patch up RMOD's PSP: JFT pointer @ 0x34-0x37 */
143
  myptr[0x34] = 0x18; /* the JFT is in the PSP itself */
151
  myptr[0x34] = 0x18; /* the JFT is in the PSP itself */
144
  myptr[0x35] = 0;
152
  myptr[0x35] = 0;
145
  myptr[0x36] = rmodseg & 0xff;
153
  myptr[0x36] = rmodseg & 0xff;
146
  myptr[0x37] = rmodseg >> 8;
154
  myptr[0x37] = rmodseg >> 8;
147
 
155
 
148
  /* patch up RMOD's PSP: pointer to previous PSP @ 0x38-0x3B */
156
  /* patch up RMOD's PSP: pointer to previous PSP @ 0x38-0x3B */
149
  myptr[0x38] = 0;
157
  myptr[0x38] = 0;
150
  myptr[0x39] = 0;
158
  myptr[0x39] = 0;
151
  myptr[0x3A] = rmodseg & 0xff;
159
  myptr[0x3A] = rmodseg & 0xff;
152
  myptr[0x3B] = rmodseg >> 8;
160
  myptr[0x3B] = rmodseg >> 8;
153
 
161
 
154
  /* copy rmod to its destination (right past the PSP I prepared) */
162
  /* copy rmod to its destination (right past the PSP I prepared) */
155
  myptr = MK_FP(rmodseg, 0x100);
163
  myptr = MK_FP(rmodseg, 0x100);
156
  _fmemcpy(myptr, rmodcore, rmodcore_len);
164
  _fmemcpy(myptr, rmodcore, rmodcore_len);
157
 
165
 
158
  /* mark rmod memory (MCB) as "self owned" */
166
  /* mark rmod memory (MCB) as "self owned" */
159
  mcb = MK_FP(rmodseg - 1, 0);
167
  mcb = MK_FP(rmodseg - 1, 0);
160
  owner = (void far *)(mcb + 1);
168
  owner = (void far *)(mcb + 1);
161
  *owner = rmodseg;
169
  *owner = rmodseg;
162
  _fmemcpy(mcb + 8, "SVARCOM", 8);
170
  _fmemcpy(mcb + 8, "SVARCOM", 8);
163
 
171
 
164
  /* mark env memory (MCB) as "owned by rmod" */
172
  /* mark env memory (MCB) as "owned by rmod" */
165
  mcb = MK_FP(envseg - 1, 0);
173
  mcb = MK_FP(envseg - 1, 0);
166
  owner = (void far *)(mcb + 1);
174
  owner = (void far *)(mcb + 1);
167
  *owner = rmodseg;
175
  *owner = rmodseg;
168
  _fmemcpy(mcb + 8, "SVARENV", 8);
176
  _fmemcpy(mcb + 8, "SVARENV", 8);
169
 
177
 
170
  /* if env block is newly allocated, fill it with a few NULLs */
178
  /* if env block is newly allocated, fill it with a few NULLs */
171
  if (envsize != 0) {
179
  if (envsize != 0) {
172
    owner = MK_FP(envseg, 0);
180
    owner = MK_FP(envseg, 0);
173
    owner[0] = 0;
181
    owner[0] = 0;
174
    owner[1] = 0;
182
    owner[1] = 0;
175
  }
183
  }
176
 
184
 
177
  /* set CTRL+BREAK handler to rmod */
185
  /* set CTRL+BREAK handler to rmod */
178
  _asm {
186
  _asm {
179
    push ax
187
    push ax
180
    push dx
188
    push dx
181
    push ds
189
    push ds
182
    mov ax, 0x2523
190
    mov ax, 0x2523
183
    mov ds, rmodseg
191
    mov ds, rmodseg
184
    mov dx, RMOD_OFFSET_BRKHANDLER
192
    mov dx, RMOD_OFFSET_BRKHANDLER
185
    int 0x21
193
    int 0x21
186
    pop ds
194
    pop ds
187
    pop dx
195
    pop dx
188
    pop ax
196
    pop ax
189
  }
197
  }
190
 
198
 
191
  /* mark the input buffer as empty */
199
  /* mark the input buffer as empty */
192
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
200
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
193
  myptr[0] = 128;  /* max acceptable length */
201
  myptr[0] = 128;  /* max acceptable length */
194
  myptr[1] = 0;    /* len of currently stored history string */
202
  myptr[1] = 0;    /* len of currently stored history string */
195
  myptr[2] = '\r'; /* string terminator */
203
  myptr[2] = '\r'; /* string terminator */
196
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
204
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
197
  myptr[4] = 0xFE; /* 2nd byte of the signature */
205
  myptr[4] = 0xFE; /* 2nd byte of the signature */
198
 
206
 
199
  /* prepare result (rmod props) */
207
  /* prepare result (rmod props) */
200
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
208
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
201
  _fmemset(res, 0, sizeof(*res));  /* zero out */
209
  _fmemset(res, 0, sizeof(*res));  /* zero out */
202
  res->rmodseg = rmodseg;          /* rmod segment */
210
  res->rmodseg = rmodseg;          /* rmod segment */
203
  res->origenvseg = origenvseg;    /* original environment segment */
211
  res->origenvseg = origenvseg;    /* original environment segment */
204
 
212
 
205
  /* write env segment to rmod's PSP */
213
  /* write env segment to rmod's PSP */
206
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
214
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
207
  *owner = envseg;
215
  *owner = envseg;
208
 
216
 
209
  /* write boot drive to rmod bootdrive field */
217
  /* write boot drive to rmod bootdrive field */
210
  _asm {
218
  _asm {
211
    push ax
219
    push ax
212
    push bx
220
    push bx
213
    push dx
221
    push dx
214
    push ds
222
    push ds
215
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
223
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
216
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
224
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
217
    add dl, 'A'-1 /* convert to a proper ASCII letter */
225
    add dl, 'A'-1 /* convert to a proper ASCII letter */
218
    /* set DS to rmodseg */
226
    /* set DS to rmodseg */
219
    mov ax, rmodseg
227
    mov ax, rmodseg
220
    mov ds, ax
228
    mov ds, ax
221
    /* write boot drive to rmod bootdrive field */
229
    /* write boot drive to rmod bootdrive field */
222
    mov bx, RMOD_OFFSET_BOOTDRIVE
230
    mov bx, RMOD_OFFSET_BOOTDRIVE
223
    mov [bx], dl
231
    mov [bx], dl
224
    pop ds
232
    pop ds
225
    pop dx
233
    pop dx
226
    pop bx
234
    pop bx
227
    pop ax
235
    pop ax
228
  }
236
  }
229
 
237
 
230
  /* save my original parent in rmod's memory */
238
  /* save my original parent in rmod's memory */
231
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
239
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
232
 
240
 
233
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
241
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
234
   * terminate and save the original handler in rmod's memory */
242
   * terminate and save the original handler in rmod's memory */
235
  {
243
  {
236
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
244
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
237
    ptr[0] = RMOD_OFFSET_ROUTINE;
245
    ptr[0] = RMOD_OFFSET_ROUTINE;
238
    ptr[1] = rmodseg;
246
    ptr[1] = rmodseg;
239
  }
247
  }
240
 
248
 
241
  return(res);
249
  return(res);
242
}
250
}
243
 
251
 
244
 
252
 
245
/* look up my parent: if it's rmod then return a ptr to its props struct,
253
/* look up my parent: if it's rmod then return a ptr to its props struct,
246
 * otherwise return NULL
254
 * otherwise return NULL
247
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
255
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
248
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
256
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
249
  unsigned short *parent = (void *)0x0C;
257
  unsigned short *parent = (void *)0x0C;
250
  unsigned short far *ptr;
258
  unsigned short far *ptr;
251
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
259
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
252
  unsigned char *cmdtail = (void *)0x80;
260
  unsigned char *cmdtail = (void *)0x80;
253
  unsigned char i;
261
  unsigned char i;
254
  /* is it rmod? */
262
  /* is it rmod? */
255
  ptr = MK_FP(*parent, 0x100);
263
  ptr = MK_FP(*parent, 0x100);
256
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
264
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
257
  /* match successfull (rmod is my parent) - but is it really a respawn?
265
  /* match successfull (rmod is my parent) - but is it really a respawn?
258
   * command-line tail should contain a single character '\r' */
266
   * command-line tail should contain a single character '\r' */
259
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
267
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
260
  cmdtail[0] = 0;
268
  cmdtail[0] = 0;
261
  cmdtail[1] = '\r';
269
  cmdtail[1] = '\r';
262
  /* */
270
  /* */
263
  return(MK_FP(*parent, 0x100 + rmodcore_len));
271
  return(MK_FP(*parent, 0x100 + rmodcore_len));
264
}
272
}
265
 
273
 
266
 
274
 
267
/* update rmod's pointer to comspec */
275
/* update rmod's pointer to comspec */
268
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
276
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
269
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
277
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
270
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
278
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
271
  if (comspecfp != NULL) {
279
  if (comspecfp != NULL) {
272
    *comspecptr = FP_OFF(comspecfp);
280
    *comspecptr = FP_OFF(comspecfp);
273
  } else {
281
  } else {
274
    *comspecptr = 0;
282
    *comspecptr = 0;
275
  }
283
  }
276
}
284
}
277
 
285
 
278
 
286
 
279
/* allocates bytes of far memory, flags it as belonging to rmod
287
/* allocates bytes of far memory, flags it as belonging to rmod
280
 * the new block can be optionally flagged as 'ident' (if not null) and zero
288
 * the new block can be optionally flagged as 'ident' (if not null) and zero
281
 * out the newly allocated memory.
289
 * out the newly allocated memory.
282
 * returns a far ptr to the allocated block, or NULL on error */
290
 * returns a far ptr to the allocated block, or NULL on error */
283
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
291
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
284
  unsigned short far *owner;
292
  unsigned short far *owner;
285
  unsigned short newseg = 0;
293
  unsigned short newseg = 0;
286
 
294
 
287
  /* ask DOS for a memory block (as high as possible) */
295
  /* ask DOS for a memory block (as high as possible) */
288
  _asm {
296
  _asm {
289
    push bx /* save initial value in BX so I can restore it later */
297
    push bx /* save initial value in BX so I can restore it later */
290
 
298
 
291
    /* get current allocation strategy and save it on stack */
299
    /* get current allocation strategy and save it on stack */
292
    mov ax, 0x5800
300
    mov ax, 0x5800
293
    int 0x21
301
    int 0x21
294
    push ax
302
    push ax
295
 
303
 
296
    /* set strategy to 'last fit, try high then low memory' */
304
    /* set strategy to 'last fit, try high then low memory' */
297
    mov ax, 0x5801
305
    mov ax, 0x5801
298
    mov bx, 0x0082
306
    mov bx, 0x0082
299
    int 0x21
307
    int 0x21
300
 
308
 
301
    /* ask for a memory block and save the given segment to rmodseg */
309
    /* ask for a memory block and save the given segment to rmodseg */
302
    mov ah, 0x48  /* Allocate Memory */
310
    mov ah, 0x48  /* Allocate Memory */
303
    mov bx, bytes
311
    mov bx, bytes
304
    add bx, 15    /* convert bytes to paragraphs */
312
    add bx, 15    /* convert bytes to paragraphs */
305
    shr bx, 1     /* bx /= 16 */
313
    shr bx, 1     /* bx /= 16 */
306
    shr bx, 1
314
    shr bx, 1
307
    shr bx, 1
315
    shr bx, 1
308
    shr bx, 1
316
    shr bx, 1
309
    int 0x21
317
    int 0x21
310
 
318
 
311
    /* error handling */
319
    /* error handling */
312
    jc FAIL
320
    jc FAIL
313
 
321
 
314
    /* save newly allocated segment to newseg */
322
    /* save newly allocated segment to newseg */
315
    mov newseg, ax
323
    mov newseg, ax
316
 
324
 
317
    FAIL:
325
    FAIL:
318
    /* restore initial allocation strategy */
326
    /* restore initial allocation strategy */
319
    mov ax, 0x5801
327
    mov ax, 0x5801
320
    pop bx
328
    pop bx
321
    int 0x21
329
    int 0x21
322
 
330
 
323
    pop bx /* restore BX to its initial value */
331
    pop bx /* restore BX to its initial value */
324
  }
332
  }
325
 
333
 
326
  if (newseg == 0) return(NULL);
334
  if (newseg == 0) return(NULL);
327
 
335
 
328
  /* mark memory as "owned by rmod" */
336
  /* mark memory as "owned by rmod" */
329
  owner = (void far *)(MK_FP(newseg - 1, 1));
337
  owner = (void far *)(MK_FP(newseg - 1, 1));
330
  *owner = rmod_seg;
338
  *owner = rmod_seg;
331
 
339
 
332
  /* set the MCB description to ident, if provided */
340
  /* set the MCB description to ident, if provided */
333
  if (ident) {
341
  if (ident) {
334
    char far *mcbdesc = MK_FP(newseg - 1, 8);
342
    char far *mcbdesc = MK_FP(newseg - 1, 8);
335
    int i;
343
    int i;
336
    _fmemset(mcbdesc, 0, 8);
344
    _fmemset(mcbdesc, 0, 8);
337
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
345
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
338
      mcbdesc[i] = ident[i];
346
      mcbdesc[i] = ident[i];
339
    }
347
    }
340
  }
348
  }
341
 
349
 
342
  /* zero out the memory before handing it out */
350
  /* zero out the memory before handing it out */
343
  _fmemset(MK_FP(newseg, 0), 0, bytes);
351
  _fmemset(MK_FP(newseg, 0), 0, bytes);
344
 
352
 
345
  return(MK_FP(newseg, 0));
353
  return(MK_FP(newseg, 0));
346
}
354
}
347
 
355
 
348
 
356
 
349
/* free memory previously allocated by rmod_fcalloc() */
357
/* free memory previously allocated by rmod_fcalloc() */
350
void rmod_ffree(void far *ptr) {
358
void rmod_ffree(void far *ptr) {
351
  unsigned short ptrseg;
359
  unsigned short ptrseg;
352
  unsigned short myseg = 0;
360
  unsigned short myseg = 0;
353
  unsigned short far *owner;
361
  unsigned short far *owner;
354
  if (ptr == NULL) return;
362
  if (ptr == NULL) return;
355
  ptrseg = FP_SEG(ptr);
363
  ptrseg = FP_SEG(ptr);
356
 
364
 
357
  /* get my own segment */
365
  /* get my own segment */
358
  _asm {
366
  _asm {
359
    mov myseg, cs
367
    mov myseg, cs
360
  }
368
  }
361
 
369
 
362
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
370
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
363
  owner = MK_FP(ptrseg - 1, 1);
371
  owner = MK_FP(ptrseg - 1, 1);
364
  *owner = myseg;
372
  *owner = myseg;
365
 
373
 
366
  /* free the memory block */
374
  /* free the memory block */
367
  _asm {
375
  _asm {
368
    push es
376
    push es
369
    mov ah, 0x49  /* Free Memory Block */
377
    mov ah, 0x49  /* Free Memory Block */
370
    mov es, ptrseg
378
    mov es, ptrseg
371
    int 0x21
379
    int 0x21
372
    pop es
380
    pop es
373
  }
381
  }
374
}
382
}
375
 
383
 
376
 
384
 
377
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
385
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
378
void rmod_free_bat_llist(struct rmod_props far *rmod) {
386
void rmod_free_bat_llist(struct rmod_props far *rmod) {
379
  while (rmod->bat != NULL) {
387
  while (rmod->bat != NULL) {
380
    struct batctx far *victim = rmod->bat;
388
    struct batctx far *victim = rmod->bat;
381
    rmod->bat = rmod->bat->parent;
389
    rmod->bat = rmod->bat->parent;
382
    rmod_ffree(victim);
390
    rmod_ffree(victim);
383
  }
391
  }
384
}
392
}
385
 
393