Subversion Repositories SvarDOS

Rev

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

Rev 987 Rev 1587
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 my own PSP where RMOD is about to land, so it has a proper PSP as well */
-
 
108
  /* take care to init the JFT (20 bytes starting at offset 0x18) to 0xff, which
-
 
109
   * essentially means "empty JFT slot" */
108
  myptr = MK_FP(rmodseg, 0);
110
  myptr = MK_FP(rmodseg, 0);
109
  {
111
  {
110
    unsigned short i;
112
    unsigned short i;
111
    char *mypsp = (void *)0;
113
    char *mypsp = (void *)0;
112
    for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
114
    for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
-
 
115
    for (i = 0x18; i < 0x18+20; i++) myptr[i] = 0xff;
113
  }
116
  }
-
 
117
 
-
 
118
  /* patch up RMOD's PSP: Parent's PSP segment @ 0x16-0x17 */
-
 
119
  myptr[0x16] = rmodseg & 0xff; /* RMOD is his own parent */
-
 
120
  myptr[0x17] = rmodseg >> 8;
-
 
121
 
-
 
122
  /* patch up RMOD's PSP: SS:SP pointer @ 0x2E-0x31 */
-
 
123
  myptr[0x2e] = 254; /* I abuse the PSP's command line tail as stack */
-
 
124
  myptr[0x2f] = 0;
-
 
125
  myptr[0x30] = rmodseg & 0xff;
-
 
126
  myptr[0x31] = rmodseg >> 8;
-
 
127
 
-
 
128
  /* patch up RMOD's PSP: JFT size @ 0x32-0x33 */
-
 
129
  myptr[0x32] = 0; /* default JFT size (max that fits without an extra allocation) */
-
 
130
  myptr[0x33] = 0;
-
 
131
 
-
 
132
  /* patch up RMOD's PSP: JFT pointer @ 0x34-0x37 */
-
 
133
  myptr[0x34] = 0x18; /* the JFT is in the PSP itself */
-
 
134
  myptr[0x35] = 0;
-
 
135
  myptr[0x36] = rmodseg & 0xff;
-
 
136
  myptr[0x37] = rmodseg >> 8;
-
 
137
 
-
 
138
  /* patch up RMOD's PSP: pointer to previous PSP @ 0x38-0x3B */
-
 
139
  myptr[0x38] = 0;
-
 
140
  myptr[0x39] = 0;
-
 
141
  myptr[0x3A] = rmodseg & 0xff;
-
 
142
  myptr[0x3B] = rmodseg >> 8;
-
 
143
 
-
 
144
  /* copy rmod to its destination (right past the PSP I prepared) */
114
  myptr = MK_FP(rmodseg, 0x100);
145
  myptr = MK_FP(rmodseg, 0x100);
115
  _fmemcpy(myptr, rmodcore, rmodcore_len);
146
  _fmemcpy(myptr, rmodcore, rmodcore_len);
116
 
147
 
117
  /* mark rmod memory as "self owned" */
148
  /* mark rmod memory (MCB) as "self owned" */
118
  mcb = MK_FP(rmodseg - 1, 0);
149
  mcb = MK_FP(rmodseg - 1, 0);
119
  owner = (void far *)(mcb + 1);
150
  owner = (void far *)(mcb + 1);
120
  *owner = rmodseg;
151
  *owner = rmodseg;
121
  _fmemcpy(mcb + 8, "SVARCOM", 8);
152
  _fmemcpy(mcb + 8, "SVARCOM", 8);
122
 
153
 
123
  /* mark env memory as "owned by rmod" */
154
  /* mark env memory (MCB) as "owned by rmod" */
124
  mcb = MK_FP(envseg - 1, 0);
155
  mcb = MK_FP(envseg - 1, 0);
125
  owner = (void far *)(mcb + 1);
156
  owner = (void far *)(mcb + 1);
126
  *owner = rmodseg;
157
  *owner = rmodseg;
127
  _fmemcpy(mcb + 8, "SVARENV", 8);
158
  _fmemcpy(mcb + 8, "SVARENV", 8);
128
 
159
 
129
  /* if env block is newly allocated, fill it with a few NULLs */
160
  /* if env block is newly allocated, fill it with a few NULLs */
130
  if (envsize != 0) {
161
  if (envsize != 0) {
131
    owner = MK_FP(envseg, 0);
162
    owner = MK_FP(envseg, 0);
132
    owner[0] = 0;
163
    owner[0] = 0;
133
    owner[1] = 0;
164
    owner[1] = 0;
134
  }
165
  }
135
 
166
 
136
  /* set CTRL+BREAK handler to rmod */
167
  /* set CTRL+BREAK handler to rmod */
137
  _asm {
168
  _asm {
138
    push ax
169
    push ax
139
    push dx
170
    push dx
140
    push ds
171
    push ds
141
    mov ax, 0x2523
172
    mov ax, 0x2523
142
    mov ds, rmodseg
173
    mov ds, rmodseg
143
    mov dx, RMOD_OFFSET_BRKHANDLER
174
    mov dx, RMOD_OFFSET_BRKHANDLER
144
    int 0x21
175
    int 0x21
145
    pop ds
176
    pop ds
146
    pop dx
177
    pop dx
147
    pop ax
178
    pop ax
148
  }
179
  }
149
 
180
 
150
  /* mark the input buffer as empty */
181
  /* mark the input buffer as empty */
151
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
182
  myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
152
  myptr[0] = 128;  /* max acceptable length */
183
  myptr[0] = 128;  /* max acceptable length */
153
  myptr[1] = 0;    /* len of currently stored history string */
184
  myptr[1] = 0;    /* len of currently stored history string */
154
  myptr[2] = '\r'; /* string terminator */
185
  myptr[2] = '\r'; /* string terminator */
155
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
186
  myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
156
  myptr[4] = 0xFE; /* 2nd byte of the signature */
187
  myptr[4] = 0xFE; /* 2nd byte of the signature */
157
 
188
 
158
  /* prepare result (rmod props) */
189
  /* prepare result (rmod props) */
159
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
190
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
160
  _fmemset(res, 0, sizeof(*res));  /* zero out */
191
  _fmemset(res, 0, sizeof(*res));  /* zero out */
161
  res->rmodseg = rmodseg;          /* rmod segment */
192
  res->rmodseg = rmodseg;          /* rmod segment */
162
  res->origenvseg = origenvseg;    /* original environment segment */
193
  res->origenvseg = origenvseg;    /* original environment segment */
163
 
194
 
164
  /* write env segment to rmod's PSP */
195
  /* write env segment to rmod's PSP */
165
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
196
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
166
  *owner = envseg;
197
  *owner = envseg;
167
 
198
 
168
  /* write boot drive to rmod bootdrive field */
199
  /* write boot drive to rmod bootdrive field */
169
  _asm {
200
  _asm {
170
    push ax
201
    push ax
171
    push bx
202
    push bx
172
    push dx
203
    push dx
173
    push ds
204
    push ds
174
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
205
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
175
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
206
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
176
    add dl, 'A'-1 /* convert to a proper ASCII letter */
207
    add dl, 'A'-1 /* convert to a proper ASCII letter */
177
    /* set DS to rmodseg */
208
    /* set DS to rmodseg */
178
    mov ax, rmodseg
209
    mov ax, rmodseg
179
    mov ds, ax
210
    mov ds, ax
180
    /* write boot drive to rmod bootdrive field */
211
    /* write boot drive to rmod bootdrive field */
181
    mov bx, RMOD_OFFSET_BOOTDRIVE
212
    mov bx, RMOD_OFFSET_BOOTDRIVE
182
    mov [bx], dl
213
    mov [bx], dl
183
    pop ds
214
    pop ds
184
    pop dx
215
    pop dx
185
    pop bx
216
    pop bx
186
    pop ax
217
    pop ax
187
  }
218
  }
188
 
219
 
189
  /* save my original parent in rmod's memory */
220
  /* save my original parent in rmod's memory */
190
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
221
  res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
191
 
222
 
192
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
223
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
193
   * terminate and save the original handler in rmod's memory */
224
   * terminate and save the original handler in rmod's memory */
194
  {
225
  {
195
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
226
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
196
    ptr[0] = RMOD_OFFSET_ROUTINE;
227
    ptr[0] = RMOD_OFFSET_ROUTINE;
197
    ptr[1] = rmodseg;
228
    ptr[1] = rmodseg;
198
  }
229
  }
199
 
230
 
200
  return(res);
231
  return(res);
201
}
232
}
202
 
233
 
203
 
234
 
204
/* look up my parent: if it's rmod then return a ptr to its props struct,
235
/* look up my parent: if it's rmod then return a ptr to its props struct,
205
 * otherwise return NULL
236
 * otherwise return NULL
206
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
237
 * I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
207
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
238
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
208
  unsigned short *parent = (void *)0x0C;
239
  unsigned short *parent = (void *)0x0C;
209
  unsigned short far *ptr;
240
  unsigned short far *ptr;
210
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
241
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
211
  unsigned char *cmdtail = (void *)0x80;
242
  unsigned char *cmdtail = (void *)0x80;
212
  unsigned char i;
243
  unsigned char i;
213
  /* is it rmod? */
244
  /* is it rmod? */
214
  ptr = MK_FP(*parent, 0x100);
245
  ptr = MK_FP(*parent, 0x100);
215
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
246
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
216
  /* match successfull (rmod is my parent) - but is it really a respawn?
247
  /* match successfull (rmod is my parent) - but is it really a respawn?
217
   * command-line tail should contain a single character '\r' */
248
   * command-line tail should contain a single character '\r' */
218
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
249
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
219
  cmdtail[0] = 0;
250
  cmdtail[0] = 0;
220
  cmdtail[1] = '\r';
251
  cmdtail[1] = '\r';
221
  /* */
252
  /* */
222
  return(MK_FP(*parent, 0x100 + rmodcore_len));
253
  return(MK_FP(*parent, 0x100 + rmodcore_len));
223
}
254
}
224
 
255
 
225
 
256
 
226
/* update rmod's pointer to comspec */
257
/* update rmod's pointer to comspec */
227
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
258
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
228
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
259
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
229
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
260
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
230
  if (comspecfp != NULL) {
261
  if (comspecfp != NULL) {
231
    *comspecptr = FP_OFF(comspecfp);
262
    *comspecptr = FP_OFF(comspecfp);
232
  } else {
263
  } else {
233
    *comspecptr = 0;
264
    *comspecptr = 0;
234
  }
265
  }
235
}
266
}
236
 
267
 
237
 
268
 
238
/* allocates bytes of far memory, flags it as belonging to rmod
269
/* allocates bytes of far memory, flags it as belonging to rmod
239
 * the new block can be optionally flagged as 'ident' (if not null) and zero
270
 * the new block can be optionally flagged as 'ident' (if not null) and zero
240
 * out the newly allocated memory.
271
 * out the newly allocated memory.
241
 * returns a far ptr to the allocated block, or NULL on error */
272
 * returns a far ptr to the allocated block, or NULL on error */
242
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
273
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
243
  unsigned short far *owner;
274
  unsigned short far *owner;
244
  unsigned short newseg = 0;
275
  unsigned short newseg = 0;
245
 
276
 
246
  /* ask DOS for a memory block (as high as possible) */
277
  /* ask DOS for a memory block (as high as possible) */
247
  _asm {
278
  _asm {
248
    push bx /* save initial value in BX so I can restore it later */
279
    push bx /* save initial value in BX so I can restore it later */
249
 
280
 
250
    /* get current allocation strategy and save it on stack */
281
    /* get current allocation strategy and save it on stack */
251
    mov ax, 0x5800
282
    mov ax, 0x5800
252
    int 0x21
283
    int 0x21
253
    push ax
284
    push ax
254
 
285
 
255
    /* set strategy to 'last fit, try high then low memory' */
286
    /* set strategy to 'last fit, try high then low memory' */
256
    mov ax, 0x5801
287
    mov ax, 0x5801
257
    mov bx, 0x0082
288
    mov bx, 0x0082
258
    int 0x21
289
    int 0x21
259
 
290
 
260
    /* ask for a memory block and save the given segment to rmodseg */
291
    /* ask for a memory block and save the given segment to rmodseg */
261
    mov ah, 0x48  /* Allocate Memory */
292
    mov ah, 0x48  /* Allocate Memory */
262
    mov bx, bytes
293
    mov bx, bytes
263
    add bx, 15    /* convert bytes to paragraphs */
294
    add bx, 15    /* convert bytes to paragraphs */
264
    shr bx, 1     /* bx /= 16 */
295
    shr bx, 1     /* bx /= 16 */
265
    shr bx, 1
296
    shr bx, 1
266
    shr bx, 1
297
    shr bx, 1
267
    shr bx, 1
298
    shr bx, 1
268
    int 0x21
299
    int 0x21
269
 
300
 
270
    /* error handling */
301
    /* error handling */
271
    jc FAIL
302
    jc FAIL
272
 
303
 
273
    /* save newly allocated segment to newseg */
304
    /* save newly allocated segment to newseg */
274
    mov newseg, ax
305
    mov newseg, ax
275
 
306
 
276
    FAIL:
307
    FAIL:
277
    /* restore initial allocation strategy */
308
    /* restore initial allocation strategy */
278
    mov ax, 0x5801
309
    mov ax, 0x5801
279
    pop bx
310
    pop bx
280
    int 0x21
311
    int 0x21
281
 
312
 
282
    pop bx /* restore BX to its initial value */
313
    pop bx /* restore BX to its initial value */
283
  }
314
  }
284
 
315
 
285
  if (newseg == 0) return(NULL);
316
  if (newseg == 0) return(NULL);
286
 
317
 
287
  /* mark memory as "owned by rmod" */
318
  /* mark memory as "owned by rmod" */
288
  owner = (void far *)(MK_FP(newseg - 1, 1));
319
  owner = (void far *)(MK_FP(newseg - 1, 1));
289
  *owner = rmod_seg;
320
  *owner = rmod_seg;
290
 
321
 
291
  /* set the MCB description to ident, if provided */
322
  /* set the MCB description to ident, if provided */
292
  if (ident) {
323
  if (ident) {
293
    char far *mcbdesc = MK_FP(newseg - 1, 8);
324
    char far *mcbdesc = MK_FP(newseg - 1, 8);
294
    int i;
325
    int i;
295
    _fmemset(mcbdesc, 0, 8);
326
    _fmemset(mcbdesc, 0, 8);
296
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
327
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
297
      mcbdesc[i] = ident[i];
328
      mcbdesc[i] = ident[i];
298
    }
329
    }
299
  }
330
  }
300
 
331
 
301
  /* zero out the memory before handing it out */
332
  /* zero out the memory before handing it out */
302
  _fmemset(MK_FP(newseg, 0), 0, bytes);
333
  _fmemset(MK_FP(newseg, 0), 0, bytes);
303
 
334
 
304
  return(MK_FP(newseg, 0));
335
  return(MK_FP(newseg, 0));
305
}
336
}
306
 
337
 
307
 
338
 
308
/* free memory previously allocated by rmod_fcalloc() */
339
/* free memory previously allocated by rmod_fcalloc() */
309
void rmod_ffree(void far *ptr) {
340
void rmod_ffree(void far *ptr) {
310
  unsigned short ptrseg;
341
  unsigned short ptrseg;
311
  unsigned short myseg = 0;
342
  unsigned short myseg = 0;
312
  unsigned short far *owner;
343
  unsigned short far *owner;
313
  if (ptr == NULL) return;
344
  if (ptr == NULL) return;
314
  ptrseg = FP_SEG(ptr);
345
  ptrseg = FP_SEG(ptr);
315
 
346
 
316
  /* get my own segment */
347
  /* get my own segment */
317
  _asm {
348
  _asm {
318
    mov myseg, cs
349
    mov myseg, cs
319
  }
350
  }
320
 
351
 
321
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
352
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
322
  owner = MK_FP(ptrseg - 1, 1);
353
  owner = MK_FP(ptrseg - 1, 1);
323
  *owner = myseg;
354
  *owner = myseg;
324
 
355
 
325
  /* free the memory block */
356
  /* free the memory block */
326
  _asm {
357
  _asm {
327
    push es
358
    push es
328
    mov ah, 0x49  /* Free Memory Block */
359
    mov ah, 0x49  /* Free Memory Block */
329
    mov es, ptrseg
360
    mov es, ptrseg
330
    int 0x21
361
    int 0x21
331
    pop es
362
    pop es
332
  }
363
  }
333
}
364
}
334
 
365
 
335
 
366
 
336
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
367
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
337
void rmod_free_bat_llist(struct rmod_props far *rmod) {
368
void rmod_free_bat_llist(struct rmod_props far *rmod) {
338
  while (rmod->bat != NULL) {
369
  while (rmod->bat != NULL) {
339
    struct batctx far *victim = rmod->bat;
370
    struct batctx far *victim = rmod->bat;
340
    rmod->bat = rmod->bat->parent;
371
    rmod->bat = rmod->bat->parent;
341
    rmod_ffree(victim);
372
    rmod_ffree(victim);
342
  }
373
  }
343
}
374
}
344
 
375