Subversion Repositories SvarDOS

Rev

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

Rev 963 Rev 975
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
    /* link in the UMB memory chain for enabling high-memory allocation (and save initial status on stack) */
59
    /* 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 */
60
    mov ax, 0x5802  /* GET UMB LINK STATE */
61
    int 0x21
61
    int 0x21
62
    xor ah, ah
62
    xor ah, ah
63
    push ax         /* save link state on stack */
63
    push ax         /* save link state on stack */
64
    mov ax, 0x5803  /* SET UMB LINK STATE */
64
    mov ax, 0x5803  /* SET UMB LINK STATE */
65
    mov bx, 1
65
    mov bx, 1
66
    int 0x21
66
    int 0x21
67
    /* get current allocation strategy and save it in DX */
67
    /* get current allocation strategy and save it in DX */
68
    mov ax, 0x5800
68
    mov ax, 0x5800
69
    int 0x21
69
    int 0x21
70
    push ax
70
    push ax
71
    pop dx
71
    pop dx
72
    /* set strategy to 'last fit, try high then low memory' */
72
    /* set strategy to 'last fit, try high then low memory' */
73
    mov ax, 0x5801
73
    mov ax, 0x5801
74
    mov bx, 0x0082
74
    mov bx, 0x0082
75
    int 0x21
75
    int 0x21
76
    /* ask for a memory block and save the given segment to rmodseg */
76
    /* ask for a memory block and save the given segment to rmodseg */
77
    mov ah, 0x48
77
    mov ah, 0x48
78
    mov bx, sizeof_rmodandprops_paras
78
    mov bx, sizeof_rmodandprops_paras
79
    int 0x21
79
    int 0x21
80
    jc ALLOC_FAIL
80
    jc ALLOC_FAIL
81
    mov rmodseg, ax
81
    mov rmodseg, ax
82
    /* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
82
    /* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
83
    mov bx, envsize
83
    mov bx, envsize
84
    test bx, bx
84
    test bx, bx
85
    jz ALLOC_FAIL
85
    jz ALLOC_FAIL
86
    mov ah, 0x48
86
    mov ah, 0x48
87
    int 0x21
87
    int 0x21
88
    jc ALLOC_FAIL
88
    jc ALLOC_FAIL
89
    mov envseg, ax
89
    mov envseg, ax
90
 
90
 
91
    ALLOC_FAIL:
91
    ALLOC_FAIL:
92
    /* restore initial allocation strategy */
92
    /* restore initial allocation strategy */
93
    mov ax, 0x5801
93
    mov ax, 0x5801
94
    mov bx, dx
94
    mov bx, dx
95
    int 0x21
95
    int 0x21
96
    /* restore initial UMB memory link state */
96
    /* restore initial UMB memory link state */
97
    mov ax, 0x5803
97
    mov ax, 0x5803
98
    pop bx       /* pop initial UMB link state from stack */
98
    pop bx       /* pop initial UMB link state from stack */
99
    int 0x21
99
    int 0x21
100
  }
100
  }
101
 
101
 
102
  if (rmodseg == 0xffff) {
102
  if (rmodseg == 0xffff) {
103
    outputnl("malloc error");
103
    outputnl("malloc error");
104
    return(NULL);
104
    return(NULL);
105
  }
105
  }
106
 
106
 
107
  /* copy rmod to its destination, prefixed with a copy of my own PSP */
107
  /* copy rmod to its destination, prefixed with a copy of my own PSP */
108
  myptr = MK_FP(rmodseg, 0);
108
  myptr = MK_FP(rmodseg, 0);
109
  {
109
  {
110
    unsigned short i;
110
    unsigned short i;
111
    char *mypsp = (void *)0;
111
    char *mypsp = (void *)0;
112
    for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
112
    for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
113
  }
113
  }
114
  myptr = MK_FP(rmodseg, 0x100);
114
  myptr = MK_FP(rmodseg, 0x100);
115
  _fmemcpy(myptr, rmodcore, rmodcore_len);
115
  _fmemcpy(myptr, rmodcore, rmodcore_len);
116
 
116
 
117
  /* mark rmod memory as "self owned" */
117
  /* mark rmod memory as "self owned" */
118
  mcb = MK_FP(rmodseg - 1, 0);
118
  mcb = MK_FP(rmodseg - 1, 0);
119
  owner = (void far *)(mcb + 1);
119
  owner = (void far *)(mcb + 1);
120
  *owner = rmodseg;
120
  *owner = rmodseg;
121
  _fmemcpy(mcb + 8, "SVARCOM", 8);
121
  _fmemcpy(mcb + 8, "SVARCOM", 8);
122
 
122
 
123
  /* mark env memory as "owned by rmod" */
123
  /* mark env memory as "owned by rmod" */
124
  mcb = MK_FP(envseg - 1, 0);
124
  mcb = MK_FP(envseg - 1, 0);
125
  owner = (void far *)(mcb + 1);
125
  owner = (void far *)(mcb + 1);
126
  *owner = rmodseg;
126
  *owner = rmodseg;
127
  _fmemcpy(mcb + 8, "SVARENV", 8);
127
  _fmemcpy(mcb + 8, "SVARENV", 8);
128
 
128
 
129
  /* if env block is newly allocated, fill it with a few NULLs */
129
  /* if env block is newly allocated, fill it with a few NULLs */
130
  if (envsize != 0) {
130
  if (envsize != 0) {
131
    owner = MK_FP(envseg, 0);
131
    owner = MK_FP(envseg, 0);
132
    owner[0] = 0;
132
    owner[0] = 0;
133
    owner[1] = 0;
133
    owner[1] = 0;
134
  }
134
  }
135
 
135
 
136
  /* set CTRL+BREAK handler to rmod */
136
  /* set CTRL+BREAK handler to rmod */
137
  _asm {
137
  _asm {
138
    push ax
138
    push ax
139
    push dx
139
    push dx
140
    push ds
140
    push ds
141
    mov ax, 0x2523
141
    mov ax, 0x2523
142
    mov ds, rmodseg
142
    mov ds, rmodseg
143
    mov dx, RMOD_OFFSET_BRKHANDLER
143
    mov dx, RMOD_OFFSET_BRKHANDLER
144
    int 0x21
144
    int 0x21
145
    pop ds
145
    pop ds
146
    pop dx
146
    pop dx
147
    pop ax
147
    pop ax
148
  }
148
  }
149
 
149
 
150
  /* prepare result (rmod props) */
150
  /* prepare result (rmod props) */
151
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
151
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
152
  _fmemset(res, 0, sizeof(*res));  /* zero out */
152
  _fmemset(res, 0, sizeof(*res));  /* zero out */
153
  res->rmodseg = rmodseg;          /* rmod segment */
153
  res->rmodseg = rmodseg;          /* rmod segment */
154
  res->inputbuf[0] = 128;          /* input buffer for INT 0x21, AH=0Ah*/
154
  res->inputbuf[0] = 128;          /* input buffer for INT 0x21, AH=0Ah*/
155
  res->origenvseg = origenvseg;    /* original environment segment */
155
  res->origenvseg = origenvseg;    /* original environment segment */
156
 
156
 
157
  /* write env segment to rmod's PSP */
157
  /* write env segment to rmod's PSP */
158
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
158
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
159
  *owner = envseg;
159
  *owner = envseg;
160
 
160
 
161
  /* write boot drive to rmod bootdrive field */
161
  /* write boot drive to rmod bootdrive field */
162
  _asm {
162
  _asm {
163
    push ax
163
    push ax
164
    push bx
164
    push bx
165
    push dx
165
    push dx
166
    push ds
166
    push ds
167
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
167
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
168
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
168
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
169
    add dl, 'A'-1 /* convert to a proper ASCII letter */
169
    add dl, 'A'-1 /* convert to a proper ASCII letter */
170
    /* set DS to rmodseg */
170
    /* set DS to rmodseg */
171
    mov ax, rmodseg
171
    mov ax, rmodseg
172
    mov ds, ax
172
    mov ds, ax
173
    /* write boot drive to rmod bootdrive field */
173
    /* write boot drive to rmod bootdrive field */
174
    mov bx, RMOD_OFFSET_BOOTDRIVE
174
    mov bx, RMOD_OFFSET_BOOTDRIVE
175
    mov [bx], dl
175
    mov [bx], dl
176
    pop ds
176
    pop ds
177
    pop dx
177
    pop dx
178
    pop bx
178
    pop bx
179
    pop ax
179
    pop ax
180
  }
180
  }
181
 
181
 
182
  /* save my original parent in rmod's memory */
182
  /* save my original parent in rmod's memory */
183
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
183
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
184
 
184
 
185
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
185
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
186
   * terminate and save the original handler in rmod's memory */
186
   * terminate and save the original handler in rmod's memory */
187
  {
187
  {
188
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
188
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
189
    ptr[0] = RMOD_OFFSET_ROUTINE;
189
    ptr[0] = RMOD_OFFSET_ROUTINE;
190
    ptr[1] = rmodseg;
190
    ptr[1] = rmodseg;
191
  }
191
  }
192
 
192
 
193
  return(res);
193
  return(res);
194
}
194
}
195
 
195
 
196
 
196
 
197
/* look up my parent: if it's rmod then return a ptr to its props struct,
197
/* look up my parent: if it's rmod then return a ptr to its props struct,
198
 * otherwise return NULL */
198
 * otherwise return NULL
-
 
199
 * since RMOD sets itself as the CTRL+BREAK handler, I look at the int23
-
 
200
 * field of the PSP to locate it. Previously I was looking at PSP[Ch] (ie.
-
 
201
 * "terminate address" but this was failing when using the LINK/LN TSR that
-
 
202
 * intercepts DOS EXEC calls and sets itself as the parent of all launched
-
 
203
 * applications */
199
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
204
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
200
  unsigned short *parent = (void *)0x0C; /* parent's seg in PSP[Ch] ("prev. int22 handler") */
205
  unsigned short *parent = (void *)0x10; /* look in PSP[10h] ("prev. int23 handler") */
201
  unsigned short far *ptr;
206
  unsigned short far *ptr;
202
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
207
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
203
  unsigned char *cmdtail = (void *)0x80;
208
  unsigned char *cmdtail = (void *)0x80;
204
  unsigned char i;
209
  unsigned char i;
205
  /* is it rmod? */
210
  /* is it rmod? */
206
  ptr = MK_FP(*parent, 0x100);
211
  ptr = MK_FP(*parent, 0x100);
207
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
212
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
208
  /* match successfull (rmod is my parent) - but is it really a respawn?
213
  /* match successfull (rmod is my parent) - but is it really a respawn?
209
   * command-line tail should contain a single character '\r' */
214
   * command-line tail should contain a single character '\r' */
210
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
215
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
211
  cmdtail[0] = 0;
216
  cmdtail[0] = 0;
212
  cmdtail[1] = '\r';
217
  cmdtail[1] = '\r';
213
  /* */
218
  /* */
214
  return(MK_FP(*parent, 0x100 + rmodcore_len));
219
  return(MK_FP(*parent, 0x100 + rmodcore_len));
215
}
220
}
216
 
221
 
217
 
222
 
218
/* update rmod's pointer to comspec */
223
/* update rmod's pointer to comspec */
219
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
224
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
220
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
225
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
221
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
226
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
222
  if (comspecfp != NULL) {
227
  if (comspecfp != NULL) {
223
    *comspecptr = FP_OFF(comspecfp);
228
    *comspecptr = FP_OFF(comspecfp);
224
  } else {
229
  } else {
225
    *comspecptr = 0;
230
    *comspecptr = 0;
226
  }
231
  }
227
}
232
}
228
 
233
 
229
 
234
 
230
/* allocates bytes of far memory, flags it as belonging to rmod
235
/* allocates bytes of far memory, flags it as belonging to rmod
231
 * the new block can be optionally flagged as 'ident' (if not null) and zero
236
 * the new block can be optionally flagged as 'ident' (if not null) and zero
232
 * out the newly allocated memory.
237
 * out the newly allocated memory.
233
 * returns a far ptr to the allocated block, or NULL on error */
238
 * returns a far ptr to the allocated block, or NULL on error */
234
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
239
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
235
  unsigned short far *owner;
240
  unsigned short far *owner;
236
  unsigned short newseg = 0;
241
  unsigned short newseg = 0;
237
 
242
 
238
  /* ask DOS for a memory block (as high as possible) */
243
  /* ask DOS for a memory block (as high as possible) */
239
  _asm {
244
  _asm {
240
    push bx /* save initial value in BX so I can restore it later */
245
    push bx /* save initial value in BX so I can restore it later */
241
 
246
 
242
    /* get current allocation strategy and save it on stack */
247
    /* get current allocation strategy and save it on stack */
243
    mov ax, 0x5800
248
    mov ax, 0x5800
244
    int 0x21
249
    int 0x21
245
    push ax
250
    push ax
246
 
251
 
247
    /* set strategy to 'last fit, try high then low memory' */
252
    /* set strategy to 'last fit, try high then low memory' */
248
    mov ax, 0x5801
253
    mov ax, 0x5801
249
    mov bx, 0x0082
254
    mov bx, 0x0082
250
    int 0x21
255
    int 0x21
251
 
256
 
252
    /* ask for a memory block and save the given segment to rmodseg */
257
    /* ask for a memory block and save the given segment to rmodseg */
253
    mov ah, 0x48  /* Allocate Memory */
258
    mov ah, 0x48  /* Allocate Memory */
254
    mov bx, bytes
259
    mov bx, bytes
255
    add bx, 15    /* convert bytes to paragraphs */
260
    add bx, 15    /* convert bytes to paragraphs */
256
    shr bx, 1     /* bx /= 16 */
261
    shr bx, 1     /* bx /= 16 */
257
    shr bx, 1
262
    shr bx, 1
258
    shr bx, 1
263
    shr bx, 1
259
    shr bx, 1
264
    shr bx, 1
260
    int 0x21
265
    int 0x21
261
 
266
 
262
    /* error handling */
267
    /* error handling */
263
    jc FAIL
268
    jc FAIL
264
 
269
 
265
    /* save newly allocated segment to newseg */
270
    /* save newly allocated segment to newseg */
266
    mov newseg, ax
271
    mov newseg, ax
267
 
272
 
268
    FAIL:
273
    FAIL:
269
    /* restore initial allocation strategy */
274
    /* restore initial allocation strategy */
270
    mov ax, 0x5801
275
    mov ax, 0x5801
271
    pop bx
276
    pop bx
272
    int 0x21
277
    int 0x21
273
 
278
 
274
    pop bx /* restore BX to its initial value */
279
    pop bx /* restore BX to its initial value */
275
  }
280
  }
276
 
281
 
277
  if (newseg == 0) return(NULL);
282
  if (newseg == 0) return(NULL);
278
 
283
 
279
  /* mark memory as "owned by rmod" */
284
  /* mark memory as "owned by rmod" */
280
  owner = (void far *)(MK_FP(newseg - 1, 1));
285
  owner = (void far *)(MK_FP(newseg - 1, 1));
281
  *owner = rmod_seg;
286
  *owner = rmod_seg;
282
 
287
 
283
  /* set the MCB description to ident, if provided */
288
  /* set the MCB description to ident, if provided */
284
  if (ident) {
289
  if (ident) {
285
    char far *mcbdesc = MK_FP(newseg - 1, 8);
290
    char far *mcbdesc = MK_FP(newseg - 1, 8);
286
    int i;
291
    int i;
287
    _fmemset(mcbdesc, 0, 8);
292
    _fmemset(mcbdesc, 0, 8);
288
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
293
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
289
      mcbdesc[i] = ident[i];
294
      mcbdesc[i] = ident[i];
290
    }
295
    }
291
  }
296
  }
292
 
297
 
293
  /* zero out the memory before handing it out */
298
  /* zero out the memory before handing it out */
294
  _fmemset(MK_FP(newseg, 0), 0, bytes);
299
  _fmemset(MK_FP(newseg, 0), 0, bytes);
295
 
300
 
296
  return(MK_FP(newseg, 0));
301
  return(MK_FP(newseg, 0));
297
}
302
}
298
 
303
 
299
 
304
 
300
/* free memory previously allocated by rmod_fcalloc() */
305
/* free memory previously allocated by rmod_fcalloc() */
301
void rmod_ffree(void far *ptr) {
306
void rmod_ffree(void far *ptr) {
302
  unsigned short ptrseg;
307
  unsigned short ptrseg;
303
  unsigned short myseg = 0;
308
  unsigned short myseg = 0;
304
  unsigned short far *owner;
309
  unsigned short far *owner;
305
  if (ptr == NULL) return;
310
  if (ptr == NULL) return;
306
  ptrseg = FP_SEG(ptr);
311
  ptrseg = FP_SEG(ptr);
307
 
312
 
308
  /* get my own segment */
313
  /* get my own segment */
309
  _asm {
314
  _asm {
310
    mov myseg, cs
315
    mov myseg, cs
311
  }
316
  }
312
 
317
 
313
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
318
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
314
  owner = MK_FP(ptrseg - 1, 1);
319
  owner = MK_FP(ptrseg - 1, 1);
315
  *owner = myseg;
320
  *owner = myseg;
316
 
321
 
317
  /* free the memory block */
322
  /* free the memory block */
318
  _asm {
323
  _asm {
319
    push es
324
    push es
320
    mov ah, 0x49  /* Free Memory Block */
325
    mov ah, 0x49  /* Free Memory Block */
321
    mov es, ptrseg
326
    mov es, ptrseg
322
    int 0x21
327
    int 0x21
323
    pop es
328
    pop es
324
  }
329
  }
325
}
330
}
326
 
331
 
327
 
332
 
328
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
333
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
329
void rmod_free_bat_llist(struct rmod_props far *rmod) {
334
void rmod_free_bat_llist(struct rmod_props far *rmod) {
330
  while (rmod->bat != NULL) {
335
  while (rmod->bat != NULL) {
331
    struct batctx far *victim = rmod->bat;
336
    struct batctx far *victim = rmod->bat;
332
    rmod->bat = rmod->bat->parent;
337
    rmod->bat = rmod->bat->parent;
333
    rmod_ffree(victim);
338
    rmod_ffree(victim);
334
  }
339
  }
335
}
340
}
336
 
341