-
Notifications
You must be signed in to change notification settings - Fork 0
/
spawn.asm
3537 lines (3534 loc) · 86.7 KB
/
spawn.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;
; --- Version 3.3 93-11-29 09:06 ---
;
; SPAWN.ASM - Main function for memory swapping spawn call.
;
; Public Domain Software written by
; Thomas Wagner
; Ferrari electronic GmbH
; Beusselstrasse 27
; D-1000 Berlin 21
; Germany
;
;>e
; Assemble with
;
; tasm /DPASCAL spawn,spawnp - Turbo Pascal (Tasm only), near
; tasm /DPASCAL /DFARCALL spawn,spawnp - Turbo Pascal (Tasm only), far
; ?asm spawn; - C, default model (small)
; ?asm /DMODL=large spawn - C, large model
;
; NOTE: For C, change the 'model' directive below according to your
; memory model, or define MODL=xxx on the command line.
;
; For Turbo C Huge model, you must give /DTC_HUGE on the
; command line, or define it here.
;
;
; Main function:
;
; PASCAL:
; function do_spawn (swapping: integer;
; execfname: string;
; cmdtail: string;
; envlen: word;
; var envp;
; stdin: string;
; stdout: string;
; stderr: string): integer;
;
; C:
; int do_spawn (int swapping,
; char *execfname,
; char *cmdtail,
; unsigned envlen,
; char *envp,
; char *stdin,
; char *stdout,
; char *stderr)
;
; Parameters:
;
; swapping - swap/spawn/exec function:
; < 0: Exec, don't swap
; 0: Spawn, don't swap
; > 0: Spawn, swap
; in this case, prep_swap must have
; been called beforehand (see below).
;
; cmdtail - command tail for EXEC.
;
; execfname - name and path of file to execute.
;
; envlen - length of environment copy (may be 0).
;
; envp - pointer to environment block (must be aligned on
; paragraph boundary). Unused if envlen is 0.
;
; 'cmdtail' and 'execfname' must be zero terminated, even when
; calling from Pascal. For Pascal, the length byte of the string
; is ignored.
;
; Returns:
; 0000..00ff: Returncode of EXECed program
; 03xx: DOS-Error xx calling EXEC
; 0500: Swapping requested, but prep_swap has not
; been called or returned an error
; 0501: MCBs don't match expected setup
; 0502: Error while swapping out
; 06xx: DOS-Error xx on redirection
;
;
; For swapping, the swap method must be prepared before calling do_spawn.
;
; PASCAL:
; function prep_swap (method: word; swapfname: string): integer;
; C:
; int prep_swap (unsigned method, char *swapfname)
;
; Parameters:
;
; method - bit-map of allowed swap devices:
; 01 - Allow EMS
; 02 - Allow XMS
; 04 - Allow File swap
; 10 - Try XMS first, then EMS
; 40 - Create file as "hidden"
; 80 - Use "create temp" call for file swap
; 100 - Don't preallocate file
; 200 - Check for Network, don't preallocate if net
; 4000 - Environment block will not be swapped
;
; swapfname - swap file name (may be undefined if the
; "method" parameters disallows file swap).
; The string must be zero terminated, even
; when calling from Pascal. For Pascal, the
; length byte of the string is ignored.
;
; Returns:
;
; A positive integer on success:
; 1 - EMS swap initialized
; 2 - XMS swap initialized
; 4 - File swap initialized
; A negative integer on failure:
; -1 - Couldn't allocate swap space
; -2 - The spawn module is located too low in memory
;<
;>d
; Assemblierung mit
;
; tasm /DPASCAL spawn,spawnp - Turbo Pascal (nur Tasm), near
; tasm /DPASCAL /DFARCALL spawn,spawnp - Turbo Pascal (nur Tasm), far
; ?asm spawn; - C, default model (small)
; ?asm /DMODL=large spawn - C, large model
;
; HINWEIS: Fr C k”nnen Sie entweder die folgende 'model'-Direktive
; Ihrem Speichermodell entsprechend „ndern, oder beim
; Assemblieren MODL=xxx in der Kommandozeile definieren.
;
; Fr Turbo C Huge model mssen Sie /DTC_HUGE beim Assemblieren
; angeben, oder das Symbol in dieser Quelle definieren.
;
;
; Haupfunktion:
;
; PASCAL:
; function do_spawn (swapping: integer;
; execfname: string;
; cmdtail: string;
; envlen: word;
; var envp)
;
; C:
; int do_spawn (int swapping,
; char *execfname,
; char *cmdtail,
; unsigned envlen,
; char *envp)
;
; Parameter:
;
; swapping - swap/spawn/exec Funktion:
; < 0: Exec, kein Auslagern, keine Rckkehr
; 0: Spawn, kein Auslagern
; > 0: Spawn, Auslagern
; in diesem Fall muá vor Aufruf die Funktion
; prep_swap aufgerufen worden sein (siehe unten).
;
; cmdtail - Parameter fr das aufgerufene Programm.
;
; execfname - Name und Pfad des auszufhrenden Programms.
;
; envlen - L„nge der Umgebungsvariablen-Kopie (kann 0 sein).
;
; envp - Zeiger auf Umgebungsvariablen-Block (muá auf Paragraph-
; Grenze adjustiert sein). Wird nicht benutzt wenn der
; envlen Parameter 0 ist.
;
; 'cmdtail' und 'execfname' mssen 0-Terminiert sein, selbst wenn
; der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal wird das
; L„ngenbyte am Anfang des Strings ignoriert.
;
; Liefert:
;
; 0000..00ff: Returncode des ausgefhrten Programms
; 03xx: DOS-Fehler xx beim Aufruf von EXEC
; 0500: Auslagern angefordert, aber prep_swap wurde
; nicht aufgerufen oder nicht erfolgreich ausgefhrt
; 0501: MCBs sind fehlerhaft bzw. ver„ndert
; 0502: Fehler bei Auslagerung
; 06xx: DOS-Fehler xx bei Redirection
;
;
; Um Auslagern zu k”nnen, muá die Auslagerungs-Methode vor Aufruf von
; do_spawn vorbereitet werden.
;
; PASCAL:
; function prep_swap (method: byte; swapfname: string): integer;
; C:
; int prep_swap (unsigned char method, char *swapfname)
;
; Parameter:
;
; method - Bit-Map der zul„ssigen Auslagerungsziele und Optionen:
; 01 - EMS zulassen
; 02 - XMS zulassen
; 04 - Datei zulassen
; 10 - Erst XMS, dann EMS versuchen
; 40 - Datei "hidden" erzeugen
; 80 - "create temp" Funktion bei Datei-Auslagerung
; 100 - Datei nicht pr„allozieren
; 200 - Netzwerk prfen, nicht pr„allozieren wenn Netz
; 4000 - Environmentblock nicht auslagern
;
; swapfname - Auslagerungsdateiname bzw. Pfad (kann undefiniert
; sein wenn der "Method" Parameter keine Dateiauslagerung
; zul„sst).
; Der String muá 0-Terminiert sein, selbst wenn
; der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal
; wird das L„ngenbyte am Anfang des Strings ignoriert.
;
; Liefert:
;
; Einen positiven Wert bei Erfolg:
; 1 - EMS Auslagerung initialisiert
; 2 - XMS Auslagerung initialisiert
; 4 - Datei-Auslagerung initialisiert
; Einen negativen Wert bei Fehler:
; -1 - Kein Platz fr Auslagerung
; -2 - Das "spawn"-Modul ist zu nah am Beginn des Programms
;<
;--------------------------------------------------------------------------
;
;>e
; Set NO_INHERIT to FALSE if you don't want do_exec to mess with
; the handle table in the PSP, and/or you do want the child process
; to inherit all open files.
; If NO_INHERIT is TRUE, only the first five handles (the standard
; ones) will be inherited, all others will be hidden. This allows
; the child to open more files, and also protects you from the child
; messing with any open handles.
; NO_INHERIT should always be TRUE if you use functions to extend
; the handle table (for more than 20 open files).
;
; Set REDIRECT to FALSE if you do not want do_spawn to support redirection.
;
; The following defines are for Turbo Pascal only:
; Set PAS_FREE to TRUE to not swap the unused heap space.
; Set TPAS_6 to TRUE for Turbo Pascal version 6.
;
; When PAS_FREE is TRUE, the unused heap, i.e. the space between
; HeapPtr and FreePtr for TP 5.x, or the space between HeapPtr and
; HeapEnd for TP6.x, is temporarily chained into the DOS free space
; list, and is not swapped out. Depending on your applications heap
; usage, this can save a large amount of swap space, and considerably
; speed up the swap.
;<
;>d
; Setzen Sie NO_INHERIT auf FALSE wenn Sie nicht wollen, daá do_spawn
; die Handle-Tabelle im PSP modifiziert, und/oder der Kindprozess
; alle offenen Dateien erben soll.
; Wenn NO_INHERIT TRUE ist, werden nur die ersten fnf Handles
; (die Standard-Handles) vererbt, alle anderen werden versteckt.
; Dies erlaubt dem Kindprozess, mehr Dateien zu ”ffnen, und schtzt
; Sie auáerdem vor Žnderungen an offenen Dateien.
; NO_INHERIT sollte stets TRUE sein, wenn Sie Funktionen zur
; Erweiterung der Handle-Tabelle (fr mehr als 20 offene Dateien)
; benutzen.
;
; Setzen Sie REDIRECT auf FALSE wenn do_spawn keine Dateiumleitung
; untersttzen soll.
;
; Die folgenden Definitionen werden nur fr Turbo Pascal ben”tigt:
; Setzen Sie PAS_FREE auf TRUE wenn der unbenutzte Heap
; nicht ausgelagert werden soll.
; Setzen Sie TPAS_6 auf TRUE fr Turbo Pascal Version 6.
;
; Wenn PAS_FREE TRUE ist, wird der nicht belegte Heap, d.h. der
; Bereich zwischen HeapPtr und FreePtr fr TP 5.x, bzw. zwischen
; HeapPtr und HeapEnd fr TP 6.x, tempor„r in die DOS-Freispeicher-
; Liste eingefgt, und damit nicht ausgelagert. Abh„ngig von der
; Heap-Belegung Ihrer Applikation kann dies den Speicherbedarf
; fr die Auslagerung wesentlich verringern, und die Auslagerung
; beschleunigen.
;<
;
FALSE = 0
TRUE = NOT FALSE
;
NO_INHERIT = TRUE
REDIRECT = FALSE
;
PAS_FREE = FALSE
TPAS_6 = FALSE
;
;
IFDEF PASCAL
.model tpascal
IFDEF FARCALL
%out Pascal, far calls
ELSE
%out Pascal, near calls
ENDIF
;
extrn prefixseg: word
IF PAS_FREE
extrn HeapPtr: dword
IF TPAS_6
extrn HeapEnd: dword
ELSE
extrn FreePtr: dword
ENDIF
ENDIF
;
ptrsize = 1
ELSE
IFNDEF MODL
.model large,c
%out large model
ELSE
% .model MODL,c
% %out MODL model
ENDIF
;
ptrsize = @DataSize
;
extrn _psp: word
ENDIF
;
public do_spawn
public prep_swap
IFNDEF PASCAL
public swap_prep
ENDIF
;
stacklen = 256 ;e local stack
;d Lokaler Stack
;
;e "ems_size" is the EMS block size: 16k.
;d "ems_size" ist die EMS-BlockgrӇe: 16k.
;
ems_size = 16 * 1024 ;e EMS block size
;d EMS-Seiten-GrӇe
ems_parasize = ems_size / 16 ;e same in paragraphs
;d desgleichen in Paragraphen
ems_shift = 10 ;e shift factor for paragraphs
;d Schiebefaktor fr Paragraphen
ems_paramask = ems_parasize-1 ;e block mask
;d Maske fr Paragraphen
;
;e "xms_size" is the unit of measurement for XMS: 1k
;d "xms_size" ist die BlockgrӇe fr XMS: 1k
;
xms_size = 1024 ;e XMS block size
;d XMS-Block-GrӇe
xms_parasize = xms_size / 16 ;e same in paragraphs
;d desgleichen in Paragraphen
xms_shift = 6 ;e shift factor for paragraphs
;d Schiebefaktor fr Paragraphen
xms_paramask = xms_parasize-1 ;e block mask
;d Maske fr Paragraphen
;
;e Method flags
;d Auslagerungsmethoden-Flags
;
USE_EMS = 01h
USE_XMS = 02h
USE_FILE = 04h
XMS_FIRST = 10h
HIDE_FILE = 40h
CREAT_TEMP = 80h
NO_PREALLOC = 100h
CHECK_NET = 200h
DONT_SWAP_ENV = 4000h
;
;e Return codes
;d Resultatcodes
;
RC_TOOLOW = 0102h
RC_BADPREP = 0500h
RC_MCBERROR = 0501h
RC_SWAPERROR = 0502h
RC_REDIRFAIL = 0600h
;
EMM_INT = 67h
;
;e The EXEC function parameter block
;d Der Parameterblock fr die EXEC-Funktion
;
exec_block struc
envseg dw ? ;e environment segment
;d Segmentadresse Umgebungsvariablenblock
ppar dw ? ;e program parameter string offset
;d Programmparameterstring Offset
pparseg dw ? ;e program parameter string segment
;d Programmparameterstring Segment
fcb1 dw ? ; FCB offset
fcb1seg dw ? ; FCB segment
fcb2 dw ? ; FCB offset
fcb2seg dw ? ; FCB segment
exec_block ends
;
;e Structure of an XMS move control block
;d Struktur eines XMS move Kontrollblocks
;
xms_control struc
lenlo dw ? ;e length to move (doubleword)
;d L„nge fr Move (Doppelwort)
lenhi dw ?
srchnd dw ? ;e source handle (0 for standard memory)
;d Quell-Handle (0 fr Standardspeicher)
srclo dw ? ;e source address (doubleword or seg:off)
;d Quell-Adresse (Doppelwort oder seg:off)
srchi dw ?
desthnd dw ? ;e destination handle (0 for standard memory)
;d Ziel-Handle (0 fr Standardspeicher)
destlo dw ? ;e destination address (doubleword or seg:off)
;d Ziel-Adresse (Doppelwort oder seg:off)
desthi dw ?
xms_control ends
;
;e The structure of the start of an MCB (memory control block)
;d Die Struktur des Beginns eines MCB (Speicher-Kontrollblock)
;
mcb struc
id db ?
owner dw ?
paras dw ?
mcb ends
;>e
; The structure of an internal MCB descriptor.
; CAUTION: This structure is assumed to be no larger than 16 bytes
; in several places in the code, and to be exactly 16 bytes when
; swapping in from file. Be careful when changing this structure.
;<
;>d
; Die Struktur eines internen MCB-Descriptors.
; ACHTUNG: An mehreren Stellen im Code wird angenommen, daá die
; L„nge dieser Struktur 16 Bytes nicht berschreitet. Beim
; Zurcklesen von Datei wird angenommen, daá die L„nge exakt 16
; Bytes betr„gt. Bei Žnderungen in dieser Struktur ist daher
; Vorsicht geboten.
;<
mcbdesc struc
addr dw ? ;e paragraph address of the MCB
;d Paragraph-Adresse des MCB
msize dw ? ;e size in paragraphs (excluding header)
;d Gr”áe in Paragraphen (Ausschlieálich Header)
swoffset dw ? ;e swap offset (0 in all blocks except first)
;d Auslagerungs-Offset (0 in allen Bl”cken
;d auáer dem ersten)
swsize dw ? ;e swap size (= msize + 1 except in first)
;d Auslagerungsgr”áe (= msize + 1 auáer
;d im ersten Block)
num_follow dw ? ;e number of following MCBs
;d Zahl der folgenden MCBs
dw 3 dup(?) ;e pad to paragraph (16 bytes)
;d Auffllen auf Paragraphen (16 Bytes)
mcbdesc ends
;
;e The variable block set up by prep_swap
;d Der Variablenblock der durch prep_swap initialisiert wird
;
prep_block struc
xmm dd ? ;e XMM entry address
;d Einsprungadresse XMM
first_mcb dw ? ;e Segment of first MCB
;d Segment des ersten MCB
psp_mcb dw ? ;e Segment of MCB of our PSP
;d Segment des MCB unseres PSP
env_mcb dw ? ;e MCB of Environment segment
;d MCB des Umgebungsvariablenblocks
noswap_mcb dw ? ;e Env MCB that may not be swapped
;d Env MCB der nicht Ausgelagert wird
IF NOT NO_INHERIT
noswap_mcb2 dw ? ;e Handle MCB that may not be swapped
;d Handle MCB der nicht Ausgelagert wird
ENDIF
IFDEF PASCAL
IF PAS_FREE
pmemid db ?
pmempar dw ?
ENDIF
ENDIF
ems_pageframe dw ? ;e EMS page frame address
;d EMS-Seiten-Adresse
handle dw ? ;e EMS/XMS/File handle
;d Handle fr EMS/XMS/Datei
total_mcbs dw ? ;e Total number of MCBs
;d Gesamtzahl MCBs
swapmethod db ? ;e Method for swapping
;d Auslagerungsmethode
swapfilename db 81 dup(?) ;e Swap file name if swapping to file
;d Auslagerungsdateiname
prep_block ends
;
;----------------------------------------------------------------------
;>e
; Since we'll be moving code and data around in memory,
; we can't address locations in the resident block with
; normal address expressions. MASM does not support
; defining variables with a fixed offset, so we have to resort
; to a kludge, and define the shrunk-down code as a structure.
; It would also be possible to use an absolute segment for the
; definition, but this is not supported by the Turbo Pascal linker.
;
; All references to low-core variables from low-core itself
; are made through DS, so we define a text macro "lmem" that
; expands to "ds:". When setting up low core from the normal
; code, ES is used to address low memory, so this can't be used.
;<
;>d
; Da Code und Daten in andere Speicherbereiche kopiert werden,
; k”nnen Adressen im residenten Teil nicht mit normalen Adress-
; ausdrcken angesprochen werden. MASM untersttzt leider nicht
; die Definition von Variablen mit festen Offsets, sodaá wir
; den residenten Teil als Struktur definieren mssen. Eine Definition
; als absolutes Segment w„re zwar in MASM m”glich, dies wird jedoch
; vom Turbo Pascal Linker nicht untersttzt.
;
; Alle Referenzen auf Variablen im residenten Teil von diesem
; Teil selbst geschehen ber DS, hierfr kann daher ein Text-Makro
; "lmem" definiert werden, das zu "ds:" expandiert wird. Beim
; Aufsetzen des residenten Teils vom normalen Programm geschieht
; die Adressierung ber ES, sodaá dieses Makro dort nicht verwendet
; werden darf.
;<
lmem equ <ds:>
;>e
; The memory structure for the shrunk-down code, excluding the
; code itself. The code follows this block.
; The start of this block is the PSP.
;<
;>d
; Die Struktur des residenten Teils, ausschlieálich des Programm-
; Codes. Der Programmcode folgt diesem Block.
; Der Beginn dieses Blocks ist der PSP.
;<
parseg struc
db 18h dup(?)
psp_handletab db 20 dup(?) ; Handle Table
psp_envptr dw ? ; Environment Pointer
dd ?
psp_handlenum dw ? ; Number of Handles (DOS >= 3.3)
psp_handleptro dw ? ; Handle Table Pointer (DOS >= 3.3)
psp_handleptrs dw ? ; Handle Table Pointer Segment
db 5ch-38h dup(?) ;e start after PSP
;d Start nach PSP
;
save_ss dw ? ;e 5C - saved global ss
;d 5C - Sicherung globales SS
save_sp dw ? ;e 5E - saved global sp
;d 5E - Sicherung globaler SP
xfcb1 db 16 dup(?) ;e 60..6F - default FCB
;d 60..6F - Standard-FCB
xfcb2 db 16 dup(?) ;e 70..7F - default FCB
;d 70..7f - Standard-FCB
zero dw ? ;e 80 Zero command tail length (dummy)
;d 80 Null-Kommandozeile (Dummy)
;
expar db TYPE exec_block dup (?) ; exec-parameter-block
spx dw ? ;e saved local sp
;d Sicherung lokaler SP
div0_off dw ? ;e divide by zero vector save
;d Sicherung divide-by-zero Vektor
div0_seg dw ?
IF NO_INHERIT
lhandlesave db 26 dup(?) ;e saved handle table and pointer
;d Sicherung Handle-Tabelle und Pointer
IF REDIRECT
lredirsav db 6 dup(?) ;e saved redirection handles
;d Sicherung Umleitungs-Handles
ENDIF
ENDIF
IF REDIRECT
lstdinsav dw 3 dup(?) ;e duped redirection handles
;d Umleitungs-Handles aus 'dup'
ENDIF
filename db 82 dup(?) ;e exec filename
;d EXEC-Dateiname
progpars db 128 dup(?) ;e command tail
;d Kommandozeile
db stacklen dup(?) ;e local stack space
;d Lokaler Stackbereich
mystack db ?
lprep db TYPE prep_block dup(?) ;e the swapping variables
;d die Auslagerungsvariablen
lcurrdesc db TYPE mcbdesc dup(?) ;e the current MCB descriptor
;d Descriptor aktueller MCB
lxmsctl db TYPE xms_control dup(?)
eretcode dw ? ;e EXEC return code
;d Resultatcode EXEC
retflags dw ? ;e EXEC return flags
;d Resultatflags EXEC
cgetmcb dw ? ;e address of get_mcb
;d Adresse von get_mcb
;
parseg ends
;
param_len = ((TYPE parseg + 1) / 2) * 2 ; make even
codebeg = param_len
;
.code
;
;------------------------------------------------------------------------
;
lowcode_begin:
;>e
; The following parts of the program code will be moved to
; low core and executed there, so there must be no absolute
; memory references.
; The call to get_mcb must be made indirect, since the offset
; from the swap-in routine to get_mcb will not be the same
; after moving.
;
;
; get_mcb allocates a block of memory by modifying the MCB chain
; directly.
;
; On entry, lcurrdesc has the mcb descriptor for the block to
; allocate.
;
; On exit, Carry is set if the block couldn't be allocated.
;
; Uses AX, BX, CX, ES
; Modifies lprep.first_mcb
;<
;>d
; Der folgende Teil des Programm-Codes wird in den unteren Speicher-
; bereich kopiert und dort ausgefhrt, es drfen daher keine
; absoluten Speicheradressen verwendet werden.
; Der Aufruf von get_mcb muá indirekt erfolgen, da der Offset
; der Einlagerungs-Routine zu get_mcb nach dem Kopieren nicht
; mehr mit der Definition bereinstimmt.
;
;
; get_mcb alloziert einen Speicherblock durch direkte Modifikation
; der MCB-Kette.
;
; Bei Einsprung enth„lt lcurrdesc den Deskriptor fr den zu
; allozierenden Block.
;
; Bei Rckkehr ist das Carry-Flag gesetzt wenn der Block nicht
; alloziert werden konnte.
;
; Benutzt AX, BX, CX, ES
; Modifiziert lprep.first_mcb
;<
get_mcb proc near
;
mov ax,lmem lprep.first_mcb
mov bx,lmem lcurrdesc.addr
;
getmcb_loop:
mov es,ax
cmp ax,bx
ja gmcb_abort ;e halt if MCB > wanted
;d Abbrechen wenn MCB > gewnschtem
je mcb_found ;e jump if same addr as wanted
;d jump wenn Adresse gleich gewnschter
add ax,es:paras ;e last addr
;d Letze Adresse
inc ax ; next mcb
cmp ax,bx
jbe getmcb_loop ;e Loop if next <= wanted
;d Nochmal wenn n„chster <= gewnschter
;
;>e
; The wanted MCB starts within the current MCB. We now have to
; create a new MCB at the wanted position, which is initially
; free, and shorten the current MCB to reflect the reduced size.
;<
;>d
; Der gewnschte MCB beginnt innerhalb des laufenden MCB. Es muá
; nun ein MCB an der gewnschten Position eingerichtet werden, und
; der laufende MCB ist zu krzen.
;<
cmp es:owner,0
jne gmcb_abort ;e halt if not free
;d Abbruch wenn nicht frei
mov bx,es ;e current
;d laufender
inc bx ;e + 1 (header doesn't count)
;d + 1 (Header z„hlt nicht)
mov ax,lmem lcurrdesc.addr
sub ax,bx ;e paragraphs between MCB and wanted
;d Paragraphen zwischen MCB
;d und gewnschtem
mov bx,es:paras ;e paras in current MCB
;d Paragraphen in laufendem MCB
sub bx,ax ;e remaining paras
;d Restliche Paragraphen
dec bx ;e -1 for header
;d -1 fr Header
mov es:paras,ax ;e set new size for current
;d neue GrӇe fr laufenden Setzen
mov cl,es:id ;e old id
;d Alte ID
mov es:id,4dh ;e set id: there is a next
;d Setze ID: es gibt einen n„chsten
mov ax,lmem lcurrdesc.addr
mov es,ax
mov es:id,cl ;e and init to free
;d und initialisiere auf Frei
mov es:owner,0
mov es:paras,bx
;>e
; We have found an MCB at the right address. If it's not free,
; abort. Else check the size. If the size is ok, we're done
; (more or less).
;<
;>d
; Wir haben einen MCB an der korrekten Adresse. Falls er nicht
; frei ist, abbrechen. Sonst GrӇe prfen. Falls die GrӇe
; korrekt ist, sind wir (mehr oder weniger) fertig.
;<
mcb_found:
mov es,ax
cmp es:owner,0
je mcb_check ;e continue if free
;d weiter wenn Frei
;
gmcb_abort:
stc
ret
;
mcb_check:
mov ax,es:paras ;e size
;d GrӇe
cmp ax,lmem lcurrdesc.msize ;e needed size
;d gewnschte GrӇe
jae mcb_ok ;e ok if enough space
;d OK wenn genug Platz
;>e
; If there's not enough room in this MCB, check if the next
; MCB is free, too. If so, coalesce both MCB's and check again.
;<
;>d
; Wenn in diesem MCB nicht genug Platz ist, den n„chsten MCB
; prfen ob er ebenfalls frei ist. Falls ja, beide Bl”cke
; kombinieren und nochmals prfen.
;<
cmp es:id,4dh
jnz gmcb_abort ;e halt if no next
;d Abbruch wenn kein n„chster
push es ;e save current
;d Laufenden sichern
mov bx,es
add ax,bx
inc ax ;e next MCB
;d n„chter MCB
mov es,ax
cmp es:owner,0 ;e next free ?
;d ist der n„chste frei?
jne gmcb_abort ;e halt if not
;d Abbruch wenn nein
mov ax,es:paras ;e else load size
;d sonst GrӇe laden
inc ax ;e + 1 for header
;d + 1 fr Header
mov cl,es:id ;e and load ID
;d und ID laden
pop es ;e back to last MCB
;d zurck zum letzten MCB
add es:paras,ax ;e increase size
;d Gr”áe erh”hen
mov es:id,cl ;e and store ID
;d und ID abspeichern
jmp mcb_check ;e now try again
;d nochmal versuchen
;>e
; The MCB is free and large enough. If it's larger than the
; wanted size, create another MCB after the wanted.
;<
;>d
; Der MCB ist frei und groá genug. Wenn er gr”áer als die gewnschte
; Gr”áe ist, muá ein weiterer MCB nach dem gewnschten erzeugt werden.
;<
mcb_ok:
mov bx,es:paras
sub bx,lmem lcurrdesc.msize
jz mcb_no_next ;e ok, no next to create
;d OK, kein neuer einzurichten
push es
dec bx ;e size of next block
;d Gr”áe des n„chsten Blocks
mov ax,es
add ax,lmem lcurrdesc.msize
inc ax ;e next MCB addr
;d Adresse des n„chsten MCB
mov cl,es:id ;e id of this block
;d ID dieses Blocks
mov es,ax ;e address next
;d n„chsten adressieren
mov es:id,cl ;e store id
;d ID abspeichern
mov es:paras,bx ;e store size
;d GrӇe abspeichern
mov es:owner,0 ;e and mark as free
;d und als frei markieren
pop es ;e back to old MCB
;d zurck zum alten MCB
mov es:id,4dh ;e mark next block present
;d markieren daá weiterer existiert
mov ax,lmem lcurrdesc.msize ;e and set size to wanted
;d und GrӇe auf gewnschte setzen
mov es:paras,ax
;
mcb_no_next:
mov es:owner,cx ;e set owner to current PSP
;d owner auf laufenden PSP setzen
;>e
; Set the 'first_mcb' pointer to the current one, so we don't
; walk through all the previous blocks the next time.
; Also, check if the block we just allocated is the environment
; segment of the program. If so, restore the environment pointer
; in the PSP.
;<
;>d
; Der 'first_mcb'-Pointer wird auf den aktuellen gesetzt,
; damit beim n„chsten Mal nicht wieder alle vorangegangenen
; Bl”cke abgelatscht werden mssen.
; Auáerdem wird der gerade allozierte Block geprft, ob es der
; Umgebungsvariablenblock des Programms ist. Wenn ja, wird der
; entsprechende Pointer im PSP wiederhergestellt.
;<
mov ax,es
mov lmem lprep.first_mcb,ax
cmp lmem lprep.env_mcb,ax
jne getmcb_finis
inc ax
mov lmem psp_envptr,ax
;
getmcb_finis:
clc
ret ;e all finished (whew!)
;d endlich geschafft
;
get_mcb endp
;
;
ireti:
iret
;
;>e
; The actual EXEC call.
; Registers on entry:
; BX = paragraphs to keep (0 if no swap)
; CX = length of environment to copy (words) or zero
; DS:SI = environment source
; ES:DI = environment destination
; (ES = our low core code segment)
;
;
; copy environment buffer down if present
;<
;>d
; Der eigentliche EXEC Aufruf.
; Register bei Einsprung:
; BX = Residente Paragraphen (0 wenn keine Auslagerung)
; CX = L„nge des Umgebungsvariablenblocks in Worten oder 0
; DS:SI = Quelladresse Umgebungsvariablenblock
; ES:DI = Zieladresse Umgebungsvariablenblock
; (ES = Adresse residenter Teil)
;
;
; Umgebungsvariablenblock nach unten kopieren wenn vorhanden
;<
doexec:
jcxz noenvcpy
rep movsw
;
noenvcpy:
push es ; DS = ES = low core = PSP
pop ds
or bx,bx
jz no_shrink
;
;e first, shrink the base memory block down.
;d Zuerst den Basisblock reduzieren.
;
mov ah,04ah
int 21h ; resize memory block
;>e
; Again walk all MCBs. This time, all blocks owned by the
; current process are released.
;<
;>d
; Wieder mal alle MCBs durchgehen. Diesmal werden alle Bl”cke
; die zu diesem Prozeá geh”ren freigegeben.
;<
mov si,lmem lprep.first_mcb
or si,si
jz no_shrink
mov dx,lmem lprep.psp_mcb
mov bx,dx
inc bx ; base PSP (MCB owner)
mov di,lmem lprep.noswap_mcb
;
free_loop:
cmp si,dx
je free_next ;e don't free base block
;d Basisblock nicht freigeben
cmp si,di
je free_next
IF NOT NO_INHERIT
cmp si,lmem lprep.noswap_mcb2
je free_next
ENDIF
mov es,si
cmp bx,es:owner ;e our process?
;d unser Prozeá?
jne free_next ;e next if not
;d n„chsten wenn nein
cmp si,lmem lprep.env_mcb ;e is this the environment block?
;d ist dies der Umgebungsvariablenblock?
jne free_noenv
mov ds:psp_envptr,0 ;e else clear PSP pointer
;d sonst PSP-pointer l”schen
;
free_noenv:
inc si
mov es,si
dec si
mov ah,049h ;e free memory block
;d Speicher freigeben
int 21h
;
free_next:
mov es,si
cmp es:id,4dh ;e normal block?
;d Normaler Block?
jne free_ready ;e ready if end of chain
;d Fertig wenn Ende der Kette
add si,es:paras ;e start + length
;d Beginn + L„nge
inc si ;e next MCB
;d N„chster MCB
jmp free_loop
;
free_ready:
mov ax,ds
mov es,ax
;
no_shrink:
mov dx,filename ;e params for exec
;d Parameter fr EXEC
mov bx,expar
mov ax,04b00h
int 21h ; exec
;>e
; Return from EXEC system call. Don't count on any register except
; CS to be restored (DOS 2.11 and previous versions killed all regs).
;<
;>d
; Rckkehr vom EXEC Aufruf. Alle Register auáer CS k”nnen zerst”rt
; sein (DOS-Versionen 2.11 und frher zerst”rten auch SS und SP).
;<
mov bx,cs
mov ds,bx
mov es,bx
cli
mov ss,bx
mov sp,lmem spx
sti
cld
mov lmem eretcode,ax ;e save return code
;d Resultatcode sichern
pushf
pop bx
mov lmem retflags,bx ;e and returned flags
;d und die gelieferten Flags
;
;e Cancel Redirection
;d Dateiumleitung aufheben
;
IF REDIRECT
IF NO_INHERIT
mov si,lredirsav
mov di,psp_handletab+5
mov cx,3
rep movsw
ENDIF
mov si,lstdinsav
xor cx,cx
;
lredirclose:
lodsw
cmp ax,-1
je lredclosenext
mov bx,ax
mov ah,46h
int 21h
;
lredclosenext:
inc cx
cmp cx,3
jb lredirclose
ENDIF
;
cmp lmem lprep.swapmethod,0
je exec_memok
jg exec_expand
;
; Terminate.
;
test lmem retflags,1 ; carry?
jnz exec_term ;e use EXEc retcode if set