Subversion Repositories SvarDOS

Rev

Rev 1597 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1597 Rev 1730
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-2024 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
59
    push bx
60
    push cx
60
    push cx
61
    push dx
61
    push dx
62
 
62
 
63
    /* 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) */
64
    mov ax, 0x5802  /* GET UMB LINK STATE */
64
    mov ax, 0x5802  /* GET UMB LINK STATE */
65
    int 0x21
65
    int 0x21
66
    xor ah, ah
66
    xor ah, ah
67
    push ax         /* save link state on stack */
67
    push ax         /* save link state on stack */
68
    mov ax, 0x5803  /* SET UMB LINK STATE */
68
    mov ax, 0x5803  /* SET UMB LINK STATE */
69
    mov bx, 1
69
    mov bx, 1
70
    int 0x21
70
    int 0x21
71
    /* get current allocation strategy and save it in DX */
71
    /* get current allocation strategy and save it in DX */
72
    mov ax, 0x5800
72
    mov ax, 0x5800
73
    int 0x21
73
    int 0x21
74
    push ax
74
    push ax
75
    pop dx
75
    pop dx
76
    /* set strategy to 'last fit, try high then low memory' */
76
    /* set strategy to 'last fit, try high then low memory' */
77
    mov ax, 0x5801
77
    mov ax, 0x5801
78
    mov bx, 0x0082
78
    mov bx, 0x0082
79
    int 0x21
79
    int 0x21
80
    /* 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 */
81
    mov ah, 0x48
81
    mov ah, 0x48
82
    mov bx, sizeof_rmodandprops_paras
82
    mov bx, sizeof_rmodandprops_paras
83
    int 0x21
83
    int 0x21
84
    jc ALLOC_FAIL
84
    jc ALLOC_FAIL
85
    mov rmodseg, ax
85
    mov rmodseg, ax
86
    /* 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) */
87
    mov bx, envsize
87
    mov bx, envsize
88
    test bx, bx
88
    test bx, bx
89
    jz ALLOC_FAIL
89
    jz ALLOC_FAIL
90
    mov ah, 0x48
90
    mov ah, 0x48
91
    int 0x21
91
    int 0x21
92
    jc ALLOC_FAIL
92
    jc ALLOC_FAIL
93
    mov envseg, ax
93
    mov envseg, ax
94
 
94
 
95
    ALLOC_FAIL:
95
    ALLOC_FAIL:
96
    /* restore initial allocation strategy */
96
    /* restore initial allocation strategy */
97
    mov ax, 0x5801
97
    mov ax, 0x5801
98
    mov bx, dx
98
    mov bx, dx
99
    int 0x21
99
    int 0x21
100
    /* restore initial UMB memory link state */
100
    /* restore initial UMB memory link state */
101
    mov ax, 0x5803
101
    mov ax, 0x5803
102
    pop bx       /* pop initial UMB link state from stack */
102
    pop bx       /* pop initial UMB link state from stack */
103
    int 0x21
103
    int 0x21
104
 
104
 
105
    pop dx
105
    pop dx
106
    pop cx
106
    pop cx
107
    pop bx
107
    pop bx
108
  }
108
  }
109
 
109
 
110
  if (rmodseg == 0xffff) {
110
  if (rmodseg == 0xffff) {
111
    outputnl("malloc error");
111
    outputnl("malloc error");
112
    return(NULL);
112
    return(NULL);
113
  }
113
  }
114
 
114
 
115
  /* generate a new PSP where RMOD is about to land */
115
  /* generate a new PSP where RMOD is about to land */
116
  _asm {
116
  _asm {
117
    push dx
117
    push dx
118
    mov ah, 0x26 /* CREATE NEW PROGRAM SEGMENT PREFIX (DOS 1+) */
118
    mov ah, 0x26 /* CREATE NEW PROGRAM SEGMENT PREFIX (DOS 1+) */
119
    mov dx, rmodseg
119
    mov dx, rmodseg
120
    int 0x21
120
    int 0x21
121
    pop dx
121
    pop dx
122
  }
122
  }
123
 
123
 
124
  myptr = MK_FP(rmodseg, 0);
124
  myptr = MK_FP(rmodseg, 0);
125
 
125
 
126
  /* patch up RMOD's PSP: Parent's PSP segment @ 0x16-0x17 */
126
  /* patch up RMOD's PSP: Parent's PSP segment @ 0x16-0x17 */
127
  myptr[0x16] = rmodseg & 0xff; /* RMOD is his own parent */
127
  myptr[0x16] = rmodseg & 0xff; /* RMOD is his own parent */
128
  myptr[0x17] = rmodseg >> 8;
128
  myptr[0x17] = rmodseg >> 8;
129
 
129
 
130
  /* 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
131
   * 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
132
   * 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:
133
   *
133
   *
134
   * "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
135
   * 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
136
   * 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
137
   * 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
138
   * 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
139
   * PSP." <https://github.com/SvarDOS/bugz/issues/38#issuecomment-1817445740>
139
   * PSP." <https://github.com/SvarDOS/bugz/issues/38#issuecomment-1817445740>
140
   */
140
   */
141
  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 */
142
  myptr[0x2f] = 0;   /* before and 64 bytes in front of me */
142
  myptr[0x2f] = 0;   /* before and 64 bytes in front of me */
143
  myptr[0x30] = rmodseg & 0xff;
143
  myptr[0x30] = rmodseg & 0xff;
144
  myptr[0x31] = rmodseg >> 8;
144
  myptr[0x31] = rmodseg >> 8;
145
 
145
 
146
  /* patch up RMOD's PSP: JFT size @ 0x32-0x33 */
146
  /* patch up RMOD's PSP: JFT size @ 0x32-0x33 */
147
  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) */
148
  myptr[0x33] = 0;
148
  myptr[0x33] = 0;
149
 
149
 
150
  /* patch up RMOD's PSP: JFT pointer @ 0x34-0x37 */
150
  /* patch up RMOD's PSP: JFT pointer @ 0x34-0x37 */
151
  myptr[0x34] = 0x18; /* the JFT is in the PSP itself */
151
  myptr[0x34] = 0x18; /* the JFT is in the PSP itself */
152
  myptr[0x35] = 0;
152
  myptr[0x35] = 0;
153
  myptr[0x36] = rmodseg & 0xff;
153
  myptr[0x36] = rmodseg & 0xff;
154
  myptr[0x37] = rmodseg >> 8;
154
  myptr[0x37] = rmodseg >> 8;
155
 
155
 
156
  /* patch up RMOD's PSP: pointer to previous PSP @ 0x38-0x3B */
156
  /* patch up RMOD's PSP: pointer to previous PSP @ 0x38-0x3B */
157
  myptr[0x38] = 0;
157
  myptr[0x38] = 0;
158
  myptr[0x39] = 0;
158
  myptr[0x39] = 0;
159
  myptr[0x3A] = rmodseg & 0xff;
159
  myptr[0x3A] = rmodseg & 0xff;
160
  myptr[0x3B] = rmodseg >> 8;
160
  myptr[0x3B] = rmodseg >> 8;
161
 
161
 
162
  /* copy rmod to its destination (right past the PSP I prepared) */
162
  /* copy rmod to its destination (right past the PSP I prepared) */
163
  myptr = MK_FP(rmodseg, 0x100);
163
  myptr = MK_FP(rmodseg, 0x100);
164
  _fmemcpy(myptr, rmodcore, rmodcore_len);
164
  _fmemcpy(myptr, rmodcore, rmodcore_len);
165
 
165
 
166
  /* mark rmod memory (MCB) as "self owned" */
166
  /* mark rmod memory (MCB) as "self owned" */
167
  mcb = MK_FP(rmodseg - 1, 0);
167
  mcb = MK_FP(rmodseg - 1, 0);
168
  owner = (void far *)(mcb + 1);
168
  owner = (void far *)(mcb + 1);
169
  *owner = rmodseg;
169
  *owner = rmodseg;
170
  _fmemcpy(mcb + 8, "SVARCOM", 8);
170
  _fmemcpy(mcb + 8, "SVARCOM", 8);
171
 
171
 
172
  /* mark env memory (MCB) as "owned by rmod" */
172
  /* mark env memory (MCB) as "owned by rmod" */
173
  mcb = MK_FP(envseg - 1, 0);
173
  mcb = MK_FP(envseg - 1, 0);
174
  owner = (void far *)(mcb + 1);
174
  owner = (void far *)(mcb + 1);
175
  *owner = rmodseg;
175
  *owner = rmodseg;
176
  _fmemcpy(mcb + 8, "SVARENV", 8);
176
  _fmemcpy(mcb + 8, "SVARENV", 8);
177
 
177
 
178
  /* 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 */
179
  if (envsize != 0) {
179
  if (envsize != 0) {
180
    owner = MK_FP(envseg, 0);
180
    owner = MK_FP(envseg, 0);
181
    owner[0] = 0;
181
    owner[0] = 0;
182
    owner[1] = 0;
182
    owner[1] = 0;
183
  }
183
  }
184
 
184
 
185
  /* set CTRL+BREAK handler to rmod */
185
  /* set CTRL+BREAK handler to rmod */
186
  _asm {
186
  _asm {
187
    push ax
187
    push ax
188
    push dx
188
    push dx
189
    push ds
189
    push ds
190
    mov ax, 0x2523
190
    mov ax, 0x2523
191
    mov ds, rmodseg
191
    mov ds, rmodseg
192
    mov dx, RMOD_OFFSET_BRKHANDLER
192
    mov dx, RMOD_OFFSET_BRKHANDLER
193
    int 0x21
193
    int 0x21
194
    pop ds
194
    pop ds
195
    pop dx
195
    pop dx
196
    pop ax
196
    pop ax
197
  }
197
  }
198
 
198
 
199
  /* mark the input buffer as empty */
199
  /* mark the input buffer as empty */
200
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
200
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
201
  myptr[0] = 128;  /* max acceptable length */
201
  myptr[0] = 128;  /* max acceptable length */
202
  myptr[1] = 0;    /* len of currently stored history string */
202
  myptr[1] = 0;    /* len of currently stored history string */
203
  myptr[2] = '\r'; /* string terminator */
203
  myptr[2] = '\r'; /* string terminator */
204
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
204
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
205
  myptr[4] = 0xFE; /* 2nd byte of the signature */
205
  myptr[4] = 0xFE; /* 2nd byte of the signature */
206
 
206
 
207
  /* prepare result (rmod props) */
207
  /* prepare result (rmod props) */
208
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
208
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
209
  _fmemset(res, 0, sizeof(*res));  /* zero out */
209
  _fmemset(res, 0, sizeof(*res));  /* zero out */
210
  res->rmodseg = rmodseg;          /* rmod segment */
210
  res->rmodseg = rmodseg;          /* rmod segment */
211
  res->origenvseg = origenvseg;    /* original environment segment */
211
  res->origenvseg = origenvseg;    /* original environment segment */
212
 
212
 
213
  /* write env segment to rmod's PSP */
213
  /* write env segment to rmod's PSP */
214
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
214
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
215
  *owner = envseg;
215
  *owner = envseg;
216
 
216
 
217
  /* write boot drive to rmod bootdrive field */
217
  /* write boot drive to rmod bootdrive field */
218
  _asm {
218
  _asm {
219
    push ax
219
    push ax
220
    push bx
220
    push bx
221
    push dx
221
    push dx
222
    push ds
222
    push ds
223
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
223
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
224
    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) */
225
    add dl, 'A'-1 /* convert to a proper ASCII letter */
225
    add dl, 'A'-1 /* convert to a proper ASCII letter */
226
    /* set DS to rmodseg */
226
    /* set DS to rmodseg */
227
    mov ax, rmodseg
227
    mov ax, rmodseg
228
    mov ds, ax
228
    mov ds, ax
229
    /* write boot drive to rmod bootdrive field */
229
    /* write boot drive to rmod bootdrive field */
230
    mov bx, RMOD_OFFSET_BOOTDRIVE
230
    mov bx, RMOD_OFFSET_BOOTDRIVE
231
    mov [bx], dl
231
    mov [bx], dl
232
    pop ds
232
    pop ds
233
    pop dx
233
    pop dx
234
    pop bx
234
    pop bx
235
    pop ax
235
    pop ax
236
  }
236
  }
237
 
237
 
238
  /* save my original int22h handler and parent in rmod's memory */
238
  /* save my original int22h handler and parent in rmod's memory */
239
  res->origint22 = *((unsigned long *)0x0a); /* original int22h handler seg:off is at 0x0a of my PSP */
239
  res->origint22 = *((unsigned long *)0x0a); /* original int22h handler seg:off is at 0x0a of my PSP */
240
  res->origparent = *((unsigned short *)0x16); /* PSP segment of my parent is at 0x16 of my PSP */
240
  res->origparent = *((unsigned short *)0x16); /* PSP segment of my parent is at 0x16 of my PSP */
241
 
241
 
242
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
242
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
243
   * terminate and save the original handler in rmod's memory */
243
   * terminate and save the original handler in rmod's memory */
244
  {
244
  {
245
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
245
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
246
    ptr[0] = RMOD_OFFSET_ROUTINE;
246
    ptr[0] = RMOD_OFFSET_ROUTINE;
247
    ptr[1] = rmodseg;
247
    ptr[1] = rmodseg;
248
  }
248
  }
249
 
249
 
250
  /* set my own parent to RMOD (this is not necessary for MS-DOS nor FreeDOS but
250
  /* set my own parent to RMOD (this is not necessary for MS-DOS nor FreeDOS but
251
   * might be on other DOS implementations) */
251
   * might be on other DOS implementations) */
252
  {
252
  {
253
    unsigned short *ptr = (void *)0x16;
253
    unsigned short *ptr = (void *)0x16;
254
    *ptr = rmodseg;
254
    *ptr = rmodseg;
255
  }
255
  }
256
 
256
 
257
  return(res);
257
  return(res);
258
}
258
}
259
 
259
 
260
 
260
 
261
/* look up my parent: if it's rmod then return a ptr to its props struct,
261
/* look up my parent: if it's rmod then return a ptr to its props struct,
262
 * otherwise return NULL
262
 * otherwise return NULL
263
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
263
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
264
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
264
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
265
  unsigned short *parent = (void *)0x0C;
265
  unsigned short *parent = (void *)0x0C;
266
  unsigned short far *ptr;
266
  unsigned short far *ptr;
267
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
267
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
268
  unsigned char *cmdtail = (void *)0x80;
268
  unsigned char *cmdtail = (void *)0x80;
269
  unsigned char i;
269
  unsigned char i;
270
  /* is it rmod? */
270
  /* is it rmod? */
271
  ptr = MK_FP(*parent, 0x100);
271
  ptr = MK_FP(*parent, 0x100);
272
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
272
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
273
  /* match successfull (rmod is my parent) - but is it really a respawn?
273
  /* match successfull (rmod is my parent) - but is it really a respawn?
274
   * command-line tail should contain a single character '\r' */
274
   * command-line tail should contain a single character '\r' */
275
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
275
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
276
  cmdtail[0] = 0;
276
  cmdtail[0] = 0;
277
  cmdtail[1] = '\r';
277
  cmdtail[1] = '\r';
278
  /* */
278
  /* */
279
  return(MK_FP(*parent, 0x100 + rmodcore_len));
279
  return(MK_FP(*parent, 0x100 + rmodcore_len));
280
}
280
}
281
 
281
 
282
 
282
 
283
/* update rmod's pointer to comspec */
283
/* update rmod's pointer to comspec */
284
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
284
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
285
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
285
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
286
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
286
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
287
  if (comspecfp != NULL) {
287
  if (comspecfp != NULL) {
288
    *comspecptr = FP_OFF(comspecfp);
288
    *comspecptr = FP_OFF(comspecfp);
289
  } else {
289
  } else {
290
    *comspecptr = 0;
290
    *comspecptr = 0;
291
  }
291
  }
292
}
292
}
293
 
293
 
294
 
294
 
295
/* allocates bytes of far memory, flags it as belonging to rmod
295
/* allocates bytes of far memory, flags it as belonging to rmod
296
 * the new block can be optionally flagged as 'ident' (if not null) and zero
296
 * the new block can be optionally flagged as 'ident' (if not null) and zero
297
 * out the newly allocated memory.
297
 * out the newly allocated memory.
298
 * returns a far ptr to the allocated block, or NULL on error */
298
 * returns a far ptr to the allocated block, or NULL on error */
299
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
299
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
300
  unsigned short far *owner;
300
  unsigned short far *owner;
301
  unsigned short newseg = 0;
301
  unsigned short newseg = 0;
302
 
302
 
303
  /* ask DOS for a memory block (as high as possible) */
303
  /* ask DOS for a memory block (as high as possible) */
304
  _asm {
304
  _asm {
305
    push bx /* save initial value in BX so I can restore it later */
305
    push bx /* save initial value in BX so I can restore it later */
306
 
306
 
307
    /* get current allocation strategy and save it on stack */
307
    /* get current allocation strategy and save it on stack */
308
    mov ax, 0x5800
308
    mov ax, 0x5800
309
    int 0x21
309
    int 0x21
310
    push ax
310
    push ax
311
 
311
 
312
    /* set strategy to 'last fit, try high then low memory' */
312
    /* set strategy to 'last fit, try high then low memory' */
313
    mov ax, 0x5801
313
    mov ax, 0x5801
314
    mov bx, 0x0082
314
    mov bx, 0x0082
315
    int 0x21
315
    int 0x21
316
 
316
 
317
    /* ask for a memory block and save the given segment to rmodseg */
317
    /* ask for a memory block and save the given segment to rmodseg */
318
    mov ah, 0x48  /* Allocate Memory */
318
    mov ah, 0x48  /* Allocate Memory */
319
    mov bx, bytes
319
    mov bx, bytes
320
    add bx, 15    /* convert bytes to paragraphs */
320
    add bx, 15    /* convert bytes to paragraphs */
321
    shr bx, 1     /* bx /= 16 */
321
    shr bx, 1     /* bx /= 16 */
322
    shr bx, 1
322
    shr bx, 1
323
    shr bx, 1
323
    shr bx, 1
324
    shr bx, 1
324
    shr bx, 1
325
    int 0x21
325
    int 0x21
326
 
326
 
327
    /* error handling */
327
    /* error handling */
328
    jc FAIL
328
    jc FAIL
329
 
329
 
330
    /* save newly allocated segment to newseg */
330
    /* save newly allocated segment to newseg */
331
    mov newseg, ax
331
    mov newseg, ax
332
 
332
 
333
    FAIL:
333
    FAIL:
334
    /* restore initial allocation strategy */
334
    /* restore initial allocation strategy */
335
    mov ax, 0x5801
335
    mov ax, 0x5801
336
    pop bx
336
    pop bx
337
    int 0x21
337
    int 0x21
338
 
338
 
339
    pop bx /* restore BX to its initial value */
339
    pop bx /* restore BX to its initial value */
340
  }
340
  }
341
 
341
 
342
  if (newseg == 0) return(NULL);
342
  if (newseg == 0) return(NULL);
343
 
343
 
344
  /* mark memory as "owned by rmod" */
344
  /* mark memory as "owned by rmod" */
345
  owner = (void far *)(MK_FP(newseg - 1, 1));
345
  owner = (void far *)(MK_FP(newseg - 1, 1));
346
  *owner = rmod_seg;
346
  *owner = rmod_seg;
347
 
347
 
348
  /* set the MCB description to ident, if provided */
348
  /* set the MCB description to ident, if provided */
349
  if (ident) {
349
  if (ident) {
350
    char far *mcbdesc = MK_FP(newseg - 1, 8);
350
    char far *mcbdesc = MK_FP(newseg - 1, 8);
351
    int i;
351
    int i;
352
    _fmemset(mcbdesc, 0, 8);
352
    _fmemset(mcbdesc, 0, 8);
353
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
353
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
354
      mcbdesc[i] = ident[i];
354
      mcbdesc[i] = ident[i];
355
    }
355
    }
356
  }
356
  }
357
 
357
 
358
  /* zero out the memory before handing it out */
358
  /* zero out the memory before handing it out */
359
  _fmemset(MK_FP(newseg, 0), 0, bytes);
359
  _fmemset(MK_FP(newseg, 0), 0, bytes);
360
 
360
 
361
  return(MK_FP(newseg, 0));
361
  return(MK_FP(newseg, 0));
362
}
362
}
363
 
363
 
364
 
364
 
365
/* free memory previously allocated by rmod_fcalloc() */
365
/* free memory previously allocated by rmod_fcalloc() */
366
void rmod_ffree(void far *ptr) {
366
void rmod_ffree(void far *ptr) {
367
  unsigned short ptrseg;
367
  unsigned short ptrseg;
368
  unsigned short myseg = 0;
368
  unsigned short myseg = 0;
369
  unsigned short far *owner;
369
  unsigned short far *owner;
370
  if (ptr == NULL) return;
370
  if (ptr == NULL) return;
371
  ptrseg = FP_SEG(ptr);
371
  ptrseg = FP_SEG(ptr);
372
 
372
 
373
  /* get my own segment */
373
  /* get my own segment */
374
  _asm {
374
  _asm {
375
    mov myseg, cs
375
    mov myseg, cs
376
  }
376
  }
377
 
377
 
378
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
378
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
379
  owner = MK_FP(ptrseg - 1, 1);
379
  owner = MK_FP(ptrseg - 1, 1);
380
  *owner = myseg;
380
  *owner = myseg;
381
 
381
 
382
  /* free the memory block */
382
  /* free the memory block */
383
  _asm {
383
  _asm {
384
    push es
384
    push es
385
    mov ah, 0x49  /* Free Memory Block */
385
    mov ah, 0x49  /* Free Memory Block */
386
    mov es, ptrseg
386
    mov es, ptrseg
387
    int 0x21
387
    int 0x21
388
    pop es
388
    pop es
389
  }
389
  }
390
}
390
}
391
 
391
 
392
 
392
 
393
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
393
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
394
void rmod_free_bat_llist(struct rmod_props far *rmod) {
394
void rmod_free_bat_llist(struct rmod_props far *rmod) {
395
  while (rmod->bat != NULL) {
395
  while (rmod->bat != NULL) {
396
    struct batctx far *victim = rmod->bat;
396
    struct batctx far *victim = rmod->bat;
397
    rmod->bat = rmod->bat->parent;
397
    rmod->bat = rmod->bat->parent;
398
    rmod_ffree(victim);
398
    rmod_ffree(victim);
399
  }
399
  }
400
}
400
}
401
 
401