Subversion Repositories SvarDOS

Rev

Rev 963 | Rev 983 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
421 mateuszvis 1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
3
 *
949 mateusz.vi 4
 * Copyright (C) 2021-2022 Mateusz Viste
421 mateuszvis 5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
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
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
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,
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
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
22
 * DEALINGS IN THE SOFTWARE.
23
 */
351 mateuszvis 24
 
25
#include <i86.h>
26
#include <string.h>
27
 
367 mateuszvis 28
#include "env.h"
369 mateuszvis 29
#include "helpers.h"
367 mateuszvis 30
 
351 mateuszvis 31
#include "rmodinit.h"
32
 
33
 
449 mateuszvis 34
/* returns far pointer to rmod's settings block on success */
479 mateuszvis 35
struct rmod_props far *rmod_install(unsigned short envsize, unsigned char *rmodcore, unsigned short rmodcore_len) {
351 mateuszvis 36
  char far *myptr, far *mcb;
37
  unsigned short far *owner;
478 mateuszvis 38
  const unsigned short sizeof_rmodandprops_paras = (0x100 + rmodcore_len + sizeof(struct rmod_props) + 15) / 16;
453 mateuszvis 39
  unsigned short rmodseg = 0xffff;
454 mateuszvis 40
  unsigned short envseg, origenvseg;
465 mateuszvis 41
  struct rmod_props far *res;
351 mateuszvis 42
 
453 mateuszvis 43
  /* read my current env segment from PSP and save it */
454 mateuszvis 44
  envseg = *((unsigned short *)0x2c);
45
  origenvseg = envseg;
351 mateuszvis 46
 
369 mateuszvis 47
  /* printf("original (PSP) env buffer at %04X\r\n", envseg); */
449 mateuszvis 48
 
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;
51
 
351 mateuszvis 52
  /* if custom envsize requested, convert it to number of paragraphs */
53
  if (envsize != 0) {
54
    envsize += 15;
55
    envsize /= 16;
56
  }
57
 
58
  _asm {
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 */
61
    int 0x21
62
    xor ah, ah
63
    push ax         /* save link state on stack */
64
    mov ax, 0x5803  /* SET UMB LINK STATE */
65
    mov bx, 1
66
    int 0x21
67
    /* get current allocation strategy and save it in DX */
68
    mov ax, 0x5800
69
    int 0x21
70
    push ax
71
    pop dx
72
    /* set strategy to 'last fit, try high then low memory' */
73
    mov ax, 0x5801
74
    mov bx, 0x0082
75
    int 0x21
76
    /* ask for a memory block and save the given segment to rmodseg */
77
    mov ah, 0x48
449 mateuszvis 78
    mov bx, sizeof_rmodandprops_paras
351 mateuszvis 79
    int 0x21
80
    jc ALLOC_FAIL
81
    mov rmodseg, ax
82
    /* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
83
    mov bx, envsize
84
    test bx, bx
85
    jz ALLOC_FAIL
86
    mov ah, 0x48
87
    int 0x21
88
    jc ALLOC_FAIL
89
    mov envseg, ax
90
 
91
    ALLOC_FAIL:
92
    /* restore initial allocation strategy */
93
    mov ax, 0x5801
94
    mov bx, dx
95
    int 0x21
96
    /* restore initial UMB memory link state */
97
    mov ax, 0x5803
98
    pop bx       /* pop initial UMB link state from stack */
99
    int 0x21
100
  }
101
 
102
  if (rmodseg == 0xffff) {
369 mateuszvis 103
    outputnl("malloc error");
449 mateuszvis 104
    return(NULL);
351 mateuszvis 105
  }
106
 
459 mateuszvis 107
  /* copy rmod to its destination, prefixed with a copy of my own PSP */
351 mateuszvis 108
  myptr = MK_FP(rmodseg, 0);
459 mateuszvis 109
  {
110
    unsigned short i;
111
    char *mypsp = (void *)0;
112
    for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
113
  }
114
  myptr = MK_FP(rmodseg, 0x100);
478 mateuszvis 115
  _fmemcpy(myptr, rmodcore, rmodcore_len);
351 mateuszvis 116
 
117
  /* mark rmod memory as "self owned" */
118
  mcb = MK_FP(rmodseg - 1, 0);
119
  owner = (void far *)(mcb + 1);
120
  *owner = rmodseg;
121
  _fmemcpy(mcb + 8, "SVARCOM", 8);
122
 
448 mateuszvis 123
  /* mark env memory as "owned by rmod" */
359 mateuszvis 124
  mcb = MK_FP(envseg - 1, 0);
125
  owner = (void far *)(mcb + 1);
126
  *owner = rmodseg;
127
  _fmemcpy(mcb + 8, "SVARENV", 8);
351 mateuszvis 128
 
449 mateuszvis 129
  /* if env block is newly allocated, fill it with a few NULLs */
130
  if (envsize != 0) {
131
    owner = MK_FP(envseg, 0);
132
    owner[0] = 0;
133
    owner[1] = 0;
134
  }
135
 
537 mateuszvis 136
  /* set CTRL+BREAK handler to rmod */
137
  _asm {
138
    push ax
139
    push dx
140
    push ds
141
    mov ax, 0x2523
142
    mov ds, rmodseg
143
    mov dx, RMOD_OFFSET_BRKHANDLER
144
    int 0x21
145
    pop ds
146
    pop dx
147
    pop ax
148
  }
149
 
449 mateuszvis 150
  /* prepare result (rmod props) */
478 mateuszvis 151
  res = MK_FP(rmodseg, 0x100 + rmodcore_len);
450 mateuszvis 152
  _fmemset(res, 0, sizeof(*res));  /* zero out */
153
  res->rmodseg = rmodseg;          /* rmod segment */
154
  res->inputbuf[0] = 128;          /* input buffer for INT 0x21, AH=0Ah*/
453 mateuszvis 155
  res->origenvseg = origenvseg;    /* original environment segment */
449 mateuszvis 156
 
459 mateuszvis 157
  /* write env segment to rmod's PSP */
351 mateuszvis 158
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
159
  *owner = envseg;
160
 
366 mateuszvis 161
  /* write boot drive to rmod bootdrive field */
162
  _asm {
163
    push ax
164
    push bx
165
    push dx
166
    push ds
167
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
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 */
170
    /* set DS to rmodseg */
171
    mov ax, rmodseg
172
    mov ds, ax
173
    /* write boot drive to rmod bootdrive field */
174
    mov bx, RMOD_OFFSET_BOOTDRIVE
175
    mov [bx], dl
176
    pop ds
177
    pop dx
178
    pop bx
179
    pop ax
180
  }
181
 
450 mateuszvis 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 */
184
 
448 mateuszvis 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 */
454 mateuszvis 187
  {
188
    unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
189
    ptr[0] = RMOD_OFFSET_ROUTINE;
190
    ptr[1] = rmodseg;
351 mateuszvis 191
  }
192
 
449 mateuszvis 193
  return(res);
351 mateuszvis 194
}
195
 
196
 
449 mateuszvis 197
/* look up my parent: if it's rmod then return a ptr to its props struct,
975 mateusz.vi 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 */
479 mateuszvis 204
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
975 mateusz.vi 205
  unsigned short *parent = (void *)0x10; /* look in PSP[10h] ("prev. int23 handler") */
448 mateuszvis 206
  unsigned short far *ptr;
207
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
465 mateuszvis 208
  unsigned char *cmdtail = (void *)0x80;
448 mateuszvis 209
  unsigned char i;
210
  /* is it rmod? */
459 mateuszvis 211
  ptr = MK_FP(*parent, 0x100);
449 mateuszvis 212
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
465 mateuszvis 213
  /* match successfull (rmod is my parent) - but is it really a respawn?
214
   * command-line tail should contain a single character '\r' */
215
  if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
216
  cmdtail[0] = 0;
217
  cmdtail[1] = '\r';
218
  /* */
478 mateuszvis 219
  return(MK_FP(*parent, 0x100 + rmodcore_len));
351 mateuszvis 220
}
367 mateuszvis 221
 
222
 
223
/* update rmod's pointer to comspec */
224
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
225
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
439 mateuszvis 226
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
367 mateuszvis 227
  if (comspecfp != NULL) {
439 mateuszvis 228
    *comspecptr = FP_OFF(comspecfp);
367 mateuszvis 229
  } else {
230
    *comspecptr = 0;
231
  }
232
}
949 mateusz.vi 233
 
234
 
235
/* allocates bytes of far memory, flags it as belonging to rmod
957 mateusz.vi 236
 * the new block can be optionally flagged as 'ident' (if not null) and zero
237
 * out the newly allocated memory.
949 mateusz.vi 238
 * returns a far ptr to the allocated block, or NULL on error */
957 mateusz.vi 239
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
949 mateusz.vi 240
  unsigned short far *owner;
241
  unsigned short newseg = 0;
242
 
243
  /* ask DOS for a memory block (as high as possible) */
244
  _asm {
245
    push bx /* save initial value in BX so I can restore it later */
246
 
247
    /* get current allocation strategy and save it on stack */
248
    mov ax, 0x5800
249
    int 0x21
250
    push ax
251
 
252
    /* set strategy to 'last fit, try high then low memory' */
253
    mov ax, 0x5801
254
    mov bx, 0x0082
255
    int 0x21
256
 
257
    /* ask for a memory block and save the given segment to rmodseg */
258
    mov ah, 0x48  /* Allocate Memory */
259
    mov bx, bytes
260
    add bx, 15    /* convert bytes to paragraphs */
261
    shr bx, 1     /* bx /= 16 */
262
    shr bx, 1
263
    shr bx, 1
264
    shr bx, 1
265
    int 0x21
266
 
267
    /* error handling */
268
    jc FAIL
269
 
270
    /* save newly allocated segment to newseg */
271
    mov newseg, ax
272
 
273
    FAIL:
274
    /* restore initial allocation strategy */
275
    mov ax, 0x5801
276
    pop bx
277
    int 0x21
278
 
279
    pop bx /* restore BX to its initial value */
280
  }
281
 
282
  if (newseg == 0) return(NULL);
283
 
284
  /* mark memory as "owned by rmod" */
285
  owner = (void far *)(MK_FP(newseg - 1, 1));
286
  *owner = rmod_seg;
287
 
288
  /* set the MCB description to ident, if provided */
289
  if (ident) {
290
    char far *mcbdesc = MK_FP(newseg - 1, 8);
291
    int i;
292
    _fmemset(mcbdesc, 0, 8);
293
    for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
294
      mcbdesc[i] = ident[i];
295
    }
296
  }
297
 
957 mateusz.vi 298
  /* zero out the memory before handing it out */
299
  _fmemset(MK_FP(newseg, 0), 0, bytes);
300
 
949 mateusz.vi 301
  return(MK_FP(newseg, 0));
302
}
303
 
304
 
957 mateusz.vi 305
/* free memory previously allocated by rmod_fcalloc() */
949 mateusz.vi 306
void rmod_ffree(void far *ptr) {
307
  unsigned short ptrseg;
308
  unsigned short myseg = 0;
309
  unsigned short far *owner;
310
  if (ptr == NULL) return;
311
  ptrseg = FP_SEG(ptr);
312
 
313
  /* get my own segment */
314
  _asm {
315
    mov myseg, cs
316
  }
317
 
318
  /* mark memory in MCB as my own, otherwise DOS might refuse to free it */
319
  owner = MK_FP(ptrseg - 1, 1);
320
  *owner = myseg;
321
 
322
  /* free the memory block */
323
  _asm {
324
    push es
325
    mov ah, 0x49  /* Free Memory Block */
326
    mov es, ptrseg
327
    int 0x21
328
    pop es
329
  }
330
}
963 mateusz.vi 331
 
332
 
333
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
334
void rmod_free_bat_llist(struct rmod_props far *rmod) {
335
  while (rmod->bat != NULL) {
336
    struct batctx far *victim = rmod->bat;
337
    rmod->bat = rmod->bat->parent;
338
    rmod_ffree(victim);
339
  }
340
}