gcc: Added mui and oop to list of standard link libraries.
[AROS.git] / arch / m68k-all / exec / setfunction.c
blob1c5403488cd16aa26cd0971d0f0227d7bbf08e08
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Patch a library or device function
6 Lang: english
7 */
8 #include <aros/config.h>
9 #include <exec/execbase.h>
10 #include <proto/intuition.h>
11 #include <aros/libcall.h>
12 #include <proto/exec.h>
13 #include <exec/rawfmt.h>
15 #include "exec_debug.h"
16 #include "exec_intern.h"
18 #ifndef DEBUG_SetFunction
19 # define DEBUG_SetFunction 0
20 #endif
21 #undef DEBUG
22 #if DEBUG_SetFunction
23 # define DEBUG 1
24 #endif
25 #include <aros/debug.h>
26 #undef kprintf
28 /* moveb %d0, %a3@+
29 * rts
31 const ULONG m68k_string = 0x16c04e75;
32 /* addql #1, %a3@
33 * rts
35 const ULONG m68k_count = 0x52934e75;
36 /* jmp %a6@(-86 * 6)
38 const ULONG m68k_serial = 0x4eeefdfc;
40 static AROS_UFH5(APTR, myRawDoFmt,
41 AROS_UFHA(CONST_STRPTR, fmt, A0),
42 AROS_UFHA(APTR, args, A1),
43 AROS_UFHA(VOID_FUNC, putch, A2),
44 AROS_UFHA(APTR, putptr, A3),
45 AROS_UFHA(struct ExecBase *, SysBase, A6))
47 AROS_USERFUNC_INIT
49 switch ((IPTR)putch) {
50 case (IPTR)RAWFMTFUNC_STRING:
51 putch = (VOID_FUNC)&m68k_string;
52 break;
53 case (IPTR)RAWFMTFUNC_COUNT:
54 putch = (VOID_FUNC)&m68k_count;
55 break;
56 case (IPTR)RAWFMTFUNC_SERIAL:
57 putch = (VOID_FUNC)&m68k_serial;
58 break;
59 default:
60 break;
63 return AROS_UFC5(APTR, ((struct IntExecBase *)SysBase)->PlatformData.realRawDoFmt,
64 AROS_UFCA(CONST_STRPTR, fmt, A0),
65 AROS_UFCA(APTR, args, A1),
66 AROS_UFCA(VOID_FUNC, putch, A2),
67 AROS_UFCA(APTR, putptr, A3),
68 AROS_UFCA(struct ExecBase *, SysBase, A6));
70 AROS_USERFUNC_EXIT
73 /*****************************************************************************
75 NAME */
77 AROS_LH3(APTR, SetFunction,
79 /* SYNOPSIS */
80 AROS_LHA(struct Library *, library, A1),
81 AROS_LHA(LONG, funcOffset, A0),
82 AROS_LHA(APTR, newFunction, D0),
84 /* LOCATION */
85 struct ExecBase *, SysBase, 70, Exec)
87 /* FUNCTION
88 Replaces a certain jumptable entry with another one. This function only
89 Forbid()s taskswitching but doesn't Disable() interrupts. You have
90 to do your own arbitration for functions which are callable from
91 interrupts.
93 INPUTS
94 library - Pointer to library structure.
95 funcOffset - Offset of the jumpvector from the library base address in
96 bytes. It's the negative LVO (library vector offset)
97 multiplied with LIB_VECTSIZE.
98 newFunction - New jumptable entry (pointer to the new function).
100 RESULT
101 Old jumptable entry (pointer to the old function).
103 NOTES
104 While it's more or less safe to patch a library vector with
105 SetFunction() it's not possible to safely remove the patch later.
106 So don't use this function if it can be avoided.
108 EXAMPLE
109 Patch of the function Open() from dos.library:
110 You can find the LVO of 5 in clib/dos_protos.h.
111 SetFunction(DOSBase, -5 * LIB_VECTSIZE, NewOpen);
112 NewOpen must be prepared with AROS_UFH macros.
114 BUGS
115 This contains a hack to fix dos.library/ramlib attempts to
116 setfunction exec functions. Because of this, a funcOffset
117 of more than 32 kB be truncated. This hack will also fix
118 other programs only using the lower 16 bits of funcOffset
119 and leaving garbage in the upper 16 bits.
121 These programs should be fixed.
123 Also, this includes a hack to fix attempt to SetFunction the
124 Exec/RawDoFmt() routine, which adds a wrapper to translate
125 'magic' AROS PutChFunc vectors to real functions.
127 SEE ALSO
128 MakeLibrary(), MakeFunctions(), SumLibrary()
130 INTERNALS
132 ******************************************************************************/
134 AROS_LIBFUNC_INIT
135 APTR ret;
136 ULONG *vecaddr;
138 D(bug("SetFunction(%s, -%lx, %lx) = ", (ULONG)library->lib_Node.ln_Name, -funcOffset, (ULONG)newFunction));
141 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
142 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
144 This also effectively limits the max offset to 32k, but this limit was
145 already in the original, though not really documented.
147 What happens is this: the prototype for the funcOffset says it is a
148 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
149 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
150 offset, without sign-extending to the upper 16 bits, in fact without
151 even clearing them. These high 16 bits will therefore contain garbage:
153 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
154 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
155 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
156 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
157 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
158 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
160 In my [ldp] opinion, the autodoc should never have said that only A0.W
161 is used for the funcOffset, while specifying a "long" in the prototype.
162 This will stay broken and this fix will stay here until we fix
163 dos.library/ramlib.
165 if (funcOffset & 0x00008000)
167 funcOffset |= 0xffff0000;
169 else
171 funcOffset &= 0x0000ffff;
174 /* AOS 3.1's locale.library wants to trample over Exec/RawDoFmt.
175 * Since the replacement does not understand the 'magic' AROS
176 * RAWFMTFUNC_xxxx vectors, we need to install a wrapper to
177 * translate those to real functions.
179 * This should not effect AROS usage of SetFunction() of
180 * RawDoFmt, as it will only end up adding about 16 m68k
181 * instructions of overhead.
183 if (library == (APTR)SysBase && funcOffset == (-87 * LIB_VECTSIZE)) {
184 ((struct IntExecBase *)SysBase)->PlatformData.realRawDoFmt = newFunction;
185 newFunction = myRawDoFmt;
189 Arbitrate for the jumptable. This isn't enough for interrupt callable
190 functions - but it need not be.
192 Forbid();
194 /* Mark the library as changed. */
195 library->lib_Flags|=LIBF_CHANGED;
197 /* The following section is coded like this (instead of using the macros),
198 because else gcc will output 64-bit muls instructions, that are not
199 present on the 68060 (and will crash it). It's faster this way, too. :) */
200 vecaddr = (APTR)((ULONG)library + funcOffset);
202 /* Get the old vector pointer */
203 ret = (APTR)*(ULONG *)(((ULONG)vecaddr)+2);
205 /* Set new vector and jmp instruction */
206 *(UWORD *)vecaddr = 0x4ef9;
207 *(ULONG *)(((ULONG)vecaddr)+2) = (ULONG)newFunction;
209 #if 1
210 CacheClearU();
211 #else
212 /* Can't use this because there are broken programs that
213 * copy code and then call SetFunction().
215 CacheClearE(vecaddr,LIB_VECTSIZE,CACRF_ClearI|CACRF_ClearD);
216 #endif
218 /* Arbitration is no longer needed */
219 Permit();
221 /* Sum the library up again */
222 SumLibrary(library);
224 D(bug("%lx\n", ret));
226 /* All done. */
227 return ret;
228 AROS_LIBFUNC_EXIT
229 } /* SetFunction */