Allow our own special C:SetPatch.
[AROS.git] / arch / m68k-all / dos / bcpl_patches.c
blob56d7ccf0a8a491c3da91fdf7bd199b9e39881eca
2 #include <aros/asmcall.h>
3 #include <string.h>
4 #include <exec/libraries.h>
5 #include <dos/dosextens.h>
6 #include <dos/dos.h>
7 #include <proto/arossupport.h>
8 #include <proto/exec.h>
9 #include <proto/dos.h>
11 #include "bcpl.h"
13 /* CallGlobVec lives in the private function (4) */
14 AROS_UFP5(LONG, CallGlobVec,
15 AROS_UFPA(LONG, function, D0),
16 AROS_UFPA(LONG, d1, D1),
17 AROS_UFPA(LONG, d2, D2),
18 AROS_UFPA(LONG, d3, D3),
19 AROS_UFPA(LONG, d4, D4));
22 /* LoadSeg() needs D1-D3 parameters for overlay hunk support */
23 AROS_UFP4(BPTR, LoadSeg_Overlay,
24 AROS_UFPA(UBYTE*, name, D1),
25 AROS_UFPA(BPTR, hunktable, D2),
26 AROS_UFPA(BPTR, fh, D3),
27 AROS_UFPA(struct DosLibrary *, DosBase, A6));
29 static AROS_ENTRY(LONG, SetPatch_noop,
30 AROS_UFHA(char *, argstr, A0),
31 AROS_UFHA(ULONG, argsize, D0),
32 struct ExecBase *, SysBase)
34 AROS_USERFUNC_INIT
36 APTR DOSBase = TaggedOpenLibrary(TAGGEDOPEN_DOS);
38 if (DOSBase) {
39 struct CommandLineInterface *cli = Cli();
40 if (cli && cli->cli_Interactive) {
41 Printf("Only AROS m68k SetPatch is supported.\n");
43 CloseLibrary(DOSBase);
46 return RETURN_WARN;
48 AROS_USERFUNC_EXIT
51 /* from C:Version */
52 static CONST_STRPTR FindSegmentVER(BPTR Segment, LONG *length)
54 while (Segment)
56 void *MySegment;
57 CONST_STRPTR MyBuffer;
58 ULONG BufferLen;
59 CONST_STRPTR EndBuffer;
60 CONST_STRPTR SegmentEnd;
62 MySegment = BADDR(Segment);
63 MyBuffer = (CONST_STRPTR) (MySegment + sizeof(BPTR));
64 BufferLen = *(ULONG *)(MySegment - sizeof(ULONG));
65 SegmentEnd = (CONST_STRPTR) (MySegment + (BufferLen - 1) * 4);
66 EndBuffer = SegmentEnd - 5;
68 while (MyBuffer < EndBuffer)
70 if (MyBuffer[0] == '$' &&
71 MyBuffer[1] == 'V' &&
72 MyBuffer[2] == 'E' &&
73 MyBuffer[3] == 'R' &&
74 MyBuffer[4] == ':')
76 CONST_STRPTR EndPtr;
78 MyBuffer += 5;
79 /* Required because some smartass could end his $VER: tag
80 * without '\0' in the segment to save space. - Piru
82 for (EndPtr = MyBuffer; EndPtr < SegmentEnd && *EndPtr; EndPtr++)
84 if (EndPtr - MyBuffer)
86 *length = EndPtr - MyBuffer;
87 return MyBuffer;
91 MyBuffer++;
94 Segment =*(BPTR *)MySegment;
96 return NULL;
99 /* Check if SetPatch includes magic $VER: string */
100 static BSTR LoadSeg_Check_SetPatch(BSTR segs, struct DosLibrary *DOSBase)
102 LONG len;
103 CONST_STRPTR ver = FindSegmentVER(segs, &len);
104 if (ver && len >= 18 + 1) {
105 if (!memcmp (ver + 1, "SetPatch AROS-m68k", 18))
106 return segs;
108 UnLoadSeg(segs);
109 return CreateSegList(SetPatch_noop);
112 AROS_UFH5(BPTR, LoadSeg_Check,
113 AROS_UFPA(UBYTE*, name, D1),
114 AROS_UFPA(BPTR, hunktable, D2),
115 AROS_UFPA(BPTR, fh, D3),
116 AROS_UFPA(APTR, LoadSeg_Original, A0),
117 AROS_UFPA(struct DosLibrary *, DOSBase, A6))
119 AROS_USERFUNC_INIT
121 UBYTE *filename;
123 /* name == NULL: Overlay LoadSeg */
124 if (name == NULL)
125 return AROS_UFC4(BPTR, LoadSeg_Overlay,
126 AROS_UFCA(UBYTE*, name, D1),
127 AROS_UFCA(BPTR, hunktable, D2),
128 AROS_UFCA(BPTR, fh, D3),
129 AROS_UFCA(struct DosLibrary *, DOSBase, A6));
131 filename = FilePart(name);
132 /* On m68k, we map AOS SetPatch to a no-op seglist,
133 * due to the fact that OS 3.x and higher's SetPatch
134 * blindly patches without checking OS versions.
136 if (stricmp(filename,"setpatch") == 0) {
137 BSTR segs = AROS_UFC2(BPTR, LoadSeg_Original,
138 AROS_UFCA(UBYTE*, name, D1),
139 AROS_UFCA(struct DosLibrary *, DOSBase, A6));
140 if (segs == BNULL)
141 return BNULL;
142 return LoadSeg_Check_SetPatch (segs, DOSBase);
144 /* Do not allow Picasso96 to load, it is not
145 * compatible with built-in AROS RTG system */
146 if (stricmp(filename,"rtg.library") == 0)
147 return BNULL;
149 /* Call original LoadSeg function */
150 return AROS_UFC2(BPTR, LoadSeg_Original,
151 AROS_UFCA(UBYTE*, name, D1),
152 AROS_UFCA(struct DosLibrary *, DOSBase, A6));
154 AROS_USERFUNC_EXIT
157 extern void *BCPL_jsr, *BCPL_rts;
158 extern const ULONG BCPL_GlobVec[(BCPL_GlobVec_NegSize + BCPL_GlobVec_PosSize) >> 2];
160 const UWORD highfunc = 37, lowfunc = 5, skipfuncs = 2;
162 #define PATCHMEM_SIZE (10 * (highfunc - lowfunc + 1 - skipfuncs) * sizeof(UWORD) + 13 * sizeof(UWORD))
164 /* This patches two compatibility problems with badly written programs:
165 * 1) Return value in both D0 and D1.
166 * 2) 1.x original DOS functions can be called without DOSBase in A6.
167 * Both "features" are original BCPL DOS side-effects.
170 static int PatchDOS(struct DosLibrary *dosbase)
172 UWORD i;
173 UWORD *asmcall, *asmmem;
174 IPTR func;
175 APTR GlobVec;
177 GlobVec = AllocMem(BCPL_GlobVec_NegSize + BCPL_GlobVec_PosSize, MEMF_PUBLIC);
178 if (GlobVec == NULL)
179 return FALSE;
181 CopyMem(BCPL_GlobVec, GlobVec, BCPL_GlobVec_NegSize + BCPL_GlobVec_PosSize);
182 GlobVec += BCPL_GlobVec_NegSize;
183 *(APTR *)(GlobVec + GV_DOSBase) = dosbase;
185 Forbid();
187 /* Use this private slot for the C-to-BCPL thunk */
188 __AROS_INITVEC(dosbase, 4);
189 __AROS_SETVECADDR(dosbase, 4, CallGlobVec);
191 asmmem = asmcall = AllocMem(PATCHMEM_SIZE, MEMF_PUBLIC);
193 for (i = lowfunc; i <= highfunc; i++)
195 if (i == 24 || i == 25)
196 continue;
197 func = (IPTR)__AROS_GETJUMPVEC(dosbase, i)->vec;
198 __AROS_SETVECADDR(dosbase, i, asmcall);
199 *asmcall++ = 0x2f0e; // MOVE.L A6,-(SP)
200 *asmcall++ = 0x4df9; // LEA dosbase,A6
201 *asmcall++ = (UWORD)((ULONG)dosbase >> 16);
202 *asmcall++ = (UWORD)((ULONG)dosbase >> 0);
203 *asmcall++ = 0x4eb9; // JSR func
204 *asmcall++ = (UWORD)(func >> 16);
205 *asmcall++ = (UWORD)(func >> 0);
206 *asmcall++ = 0x2C5F; // MOVE.L (SP)+,A6
207 *asmcall++ = 0x2200; // MOVE.L D0,D1
208 *asmcall++ = 0x4e75; // RTS
211 /* LoadSeg() patch */
212 func = (IPTR)__AROS_GETJUMPVEC(dosbase, 25)->vec;
213 __AROS_SETVECADDR(dosbase, 25, asmcall);
214 *asmcall++ = 0x2f0e; // MOVE.L A6,-(SP)
215 *asmcall++ = 0x4df9; // LEA dosbase,A6
216 *asmcall++ = (UWORD)((ULONG)dosbase >> 16);
217 *asmcall++ = (UWORD)((ULONG)dosbase >> 0);
218 *asmcall++ = 0x41f9; // LEA func,A0
219 *asmcall++ = (UWORD)(func >> 16);
220 *asmcall++ = (UWORD)(func >> 0);
221 *asmcall++ = 0x4eb9; // jsr func
222 *asmcall++ = (UWORD)((ULONG)LoadSeg_Check >> 16);
223 *asmcall++ = (UWORD)((ULONG)LoadSeg_Check >> 0);
224 *asmcall++ = 0x2C5F; // MOVE.L (SP)+,A6
225 *asmcall++ = 0x2200; // MOVE.L D0,D1
226 *asmcall++ = 0x4e75; // RTS
228 CacheClearE(asmmem, PATCHMEM_SIZE, CACRF_ClearI|CACRF_ClearD);
230 dosbase->dl_A5 = (LONG)&BCPL_jsr;
231 dosbase->dl_A6 = (LONG)&BCPL_rts;
232 dosbase->dl_GV = (APTR)GlobVec;
234 Permit();
236 return TRUE;
239 ADD2INITLIB(PatchDOS, 0)
241 static int UnPatchDOS(struct DosLibrary *dosbase)
243 APTR asmcall;
245 asmcall = __AROS_GETJUMPVEC(dosbase, lowfunc)->vec;
246 FreeMem(asmcall, PATCHMEM_SIZE);
247 FreeMem(dosbase->dl_GV - BCPL_GlobVec_NegSize, BCPL_GlobVec_NegSize + BCPL_GlobVec_PosSize);
249 return TRUE;
252 ADD2EXPUNGELIB(UnPatchDOS, 0)