Subversion Repositories SvarDOS

Rev

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

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