Subversion Repositories SvarDOS

Rev

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

Rev 439 Rev 448
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 Mateusz Viste
4
 * Copyright (C) 2021 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 "rmod.h"
31
#include "rmod.h"
32
 
32
 
33
#include "rmodinit.h"
33
#include "rmodinit.h"
34
 
34
 
35
 
35
 
36
/* returns segment where rmod is installed */
36
/* returns segment where rmod is installed */
37
unsigned short rmod_install(unsigned short envsize) {
37
unsigned short rmod_install(unsigned short envsize) {
38
  char far *myptr, far *mcb;
38
  char far *myptr, far *mcb;
39
  unsigned short far *owner;
39
  unsigned short far *owner;
40
  unsigned int rmodseg = 0xffff;
40
  unsigned int rmodseg = 0xffff;
41
  unsigned int envseg = 0;
41
  unsigned int envseg = 0;
42
 
42
 
43
  /* read my current env segment from PSP */
43
  /* read my current env segment from PSP */
44
  _asm {
44
  _asm {
45
    push ax
45
    push ax
46
    push bx
46
    push bx
47
    mov bx, 0x2c
47
    mov bx, 0x2c
48
    mov ax, [bx]
48
    mov ax, [bx]
49
    mov envseg, ax
49
    mov envseg, ax
50
    pop bx
50
    pop bx
51
    pop ax
51
    pop ax
52
  }
52
  }
53
 
53
 
54
  /* printf("original (PSP) env buffer at %04X\r\n", envseg); */
54
  /* printf("original (PSP) env buffer at %04X\r\n", envseg); */
55
  /* if custom envsize requested, convert it to number of paragraphs */
55
  /* if custom envsize requested, convert it to number of paragraphs */
56
  if (envsize != 0) {
56
  if (envsize != 0) {
57
    envsize += 15;
57
    envsize += 15;
58
    envsize /= 16;
58
    envsize /= 16;
59
  }
59
  }
60
 
60
 
61
 
61
 
62
  _asm {
62
  _asm {
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, (rmod_len + 15) / 16
82
    mov bx, (rmod_len + 15) / 16
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
 
105
 
106
  if (rmodseg == 0xffff) {
106
  if (rmodseg == 0xffff) {
107
    outputnl("malloc error");
107
    outputnl("malloc error");
108
    return(0xffff);
108
    return(0xffff);
109
  }
109
  }
110
 
110
 
111
  /* copy rmod to its destination */
111
  /* copy rmod to its destination */
112
  myptr = MK_FP(rmodseg, 0);
112
  myptr = MK_FP(rmodseg, 0);
113
  _fmemcpy(myptr, rmod, rmod_len);
113
  _fmemcpy(myptr, rmod, rmod_len);
114
 
114
 
115
  /* mark rmod memory as "self owned" */
115
  /* mark rmod memory as "self owned" */
116
  mcb = MK_FP(rmodseg - 1, 0);
116
  mcb = MK_FP(rmodseg - 1, 0);
117
  owner = (void far *)(mcb + 1);
117
  owner = (void far *)(mcb + 1);
118
  *owner = rmodseg;
118
  *owner = rmodseg;
119
  _fmemcpy(mcb + 8, "SVARCOM", 8);
119
  _fmemcpy(mcb + 8, "SVARCOM", 8);
120
 
120
 
121
  /* mark env memory as "self owned" */
121
  /* mark env memory as "owned by rmod" */
122
  mcb = MK_FP(envseg - 1, 0);
122
  mcb = MK_FP(envseg - 1, 0);
123
  owner = (void far *)(mcb + 1);
123
  owner = (void far *)(mcb + 1);
124
  *owner = rmodseg;
124
  *owner = rmodseg;
125
  _fmemcpy(mcb + 8, "SVARENV", 8);
125
  _fmemcpy(mcb + 8, "SVARENV", 8);
126
 
126
 
127
  /* write env segment to rmod buffer */
127
  /* write env segment to rmod buffer */
128
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
128
  owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
129
  *owner = envseg;
129
  *owner = envseg;
130
 
130
 
131
  /* write boot drive to rmod bootdrive field */
131
  /* write boot drive to rmod bootdrive field */
132
  _asm {
132
  _asm {
133
    push ax
133
    push ax
134
    push bx
134
    push bx
135
    push dx
135
    push dx
136
    push ds
136
    push ds
137
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
137
    mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
138
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
138
    int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
139
    add dl, 'A'-1 /* convert to a proper ASCII letter */
139
    add dl, 'A'-1 /* convert to a proper ASCII letter */
140
    /* set DS to rmodseg */
140
    /* set DS to rmodseg */
141
    mov ax, rmodseg
141
    mov ax, rmodseg
142
    mov ds, ax
142
    mov ds, ax
143
    /* write boot drive to rmod bootdrive field */
143
    /* write boot drive to rmod bootdrive field */
144
    mov bx, RMOD_OFFSET_BOOTDRIVE
144
    mov bx, RMOD_OFFSET_BOOTDRIVE
145
    mov [bx], dl
145
    mov [bx], dl
146
    pop ds
146
    pop ds
147
    pop dx
147
    pop dx
148
    pop bx
148
    pop bx
149
    pop ax
149
    pop ax
150
  }
150
  }
151
 
151
 
152
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I terminate */
152
  /* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
-
 
153
   * terminate and save the original handler in rmod's memory */
153
  _asm {
154
  _asm {
154
    push ax
155
    push ax
155
    push bx
156
    push bx
-
 
157
    push si
-
 
158
    push di
-
 
159
    push es
-
 
160
 
-
 
161
    /* save my original parent in rmod's memory */
-
 
162
    mov es, [rmodseg]
-
 
163
    mov si, 0x0a
-
 
164
    mov di, RMOD_OFFSET_ORIGPARENT
-
 
165
    cld
-
 
166
    movsw  /* mov ES:[DI], DS:[SI] and SI += 2 and DI += 2 */
-
 
167
    movsw
-
 
168
 
156
    mov bx, 0x0a                   /* int22 handler is at 0x0A of the PSP */
169
    mov bx, 0x0a                   /* int22 handler is at 0x0A of the PSP */
157
    mov ax, RMOD_OFFSET_ROUTINE
170
    mov ax, RMOD_OFFSET_ROUTINE
158
    mov [bx], ax                   /* int handler offset */
171
    mov [bx], ax                   /* int handler offset */
159
    mov ax, rmodseg
172
    mov ax, rmodseg
160
    mov [bx+2], ax                 /* int handler segment */
173
    mov [bx+2], ax                 /* int handler segment */
-
 
174
 
-
 
175
    pop es
-
 
176
    pop di
-
 
177
    pop si
161
    pop bx
178
    pop bx
162
    pop ax
179
    pop ax
163
  }
180
  }
164
 
181
 
165
  return(rmodseg);
182
  return(rmodseg);
166
}
183
}
167
 
184
 
168
 
185
 
169
/* scan memory for rmod, returns its segment if found, 0xffff otherwise */
186
/* look up my parent: if it's rmod then return its segment,
-
 
187
 * otherwise return 0xffff */
170
unsigned short rmod_find(void) {
188
unsigned short rmod_find(void) {
171
  unsigned short i;
-
 
172
  unsigned short far *ptrword;
189
  unsigned short *parent = (void *)0x0C; /* parent's seg in PSP[Ch] ("prev. int22 handler") */
173
  unsigned char far *ptrbyte;
190
  unsigned short far *ptr;
174
 
-
 
175
  /* iterate over all paragraphs, looking for my signature */
191
  const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
176
  for (i = 1; i != 65535; i++) {
-
 
177
    ptrword = MK_FP(i, 0);
192
  unsigned char i;
178
    if (ptrword[0] != 0x1983) continue;
-
 
179
    if (ptrword[1] != 0x1985) continue;
-
 
180
    if (ptrword[2] != 0x2017) continue;
-
 
181
    if (ptrword[3] != 0x2019) continue;
-
 
182
    /* extra check: make sure the paragraph before is an MCB block and that it
-
 
183
     * belongs to itself. otherwise I could find the rmod code embedded inside
-
 
184
     * the command.com binary... */
193
  /* is it rmod? */
185
    ptrbyte = MK_FP(i - 1, 0);
194
  ptr = MK_FP(*parent, 0);
186
    if ((*ptrbyte != 'M') && (*ptrbyte != 'Z')) continue; /* not an MCB */
195
  for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(0xffff);
187
    ptrword = MK_FP(i - 1, 1);
-
 
188
    if (*ptrword != i) continue; /* not belonging to self */
196
  /* match successfull (rmod is my parent) */
189
    return(i);
-
 
190
  }
-
 
191
  return(0xffff);
197
  return(*parent);
192
}
198
}
193
 
199
 
194
 
200
 
195
/* update rmod's pointer to comspec */
201
/* update rmod's pointer to comspec */
196
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
202
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
197
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
203
  unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
198
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
204
  char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
199
  if (comspecfp != NULL) {
205
  if (comspecfp != NULL) {
200
    *comspecptr = FP_OFF(comspecfp);
206
    *comspecptr = FP_OFF(comspecfp);
201
  } else {
207
  } else {
202
    *comspecptr = 0;
208
    *comspecptr = 0;
203
  }
209
  }
204
}
210
}
205
 
211