2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Patch a library or device function
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
25 #include <aros/debug.h>
28 /* See rom/kernel/setfunction.c for documentation */
33 const ULONG m68k_string
= 0x16c04e75;
37 const ULONG m68k_count
= 0x52934e75;
40 const ULONG m68k_serial
= 0x4eeefdfc;
42 static AROS_UFH5(APTR
, myRawDoFmt
,
43 AROS_UFHA(CONST_STRPTR
, fmt
, A0
),
44 AROS_UFHA(APTR
, args
, A1
),
45 AROS_UFHA(VOID_FUNC
, putch
, A2
),
46 AROS_UFHA(APTR
, putptr
, A3
),
47 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
51 switch ((IPTR
)putch
) {
52 case (IPTR
)RAWFMTFUNC_STRING
:
53 putch
= (VOID_FUNC
)&m68k_string
;
55 case (IPTR
)RAWFMTFUNC_COUNT
:
56 putch
= (VOID_FUNC
)&m68k_count
;
58 case (IPTR
)RAWFMTFUNC_SERIAL
:
59 putch
= (VOID_FUNC
)&m68k_serial
;
65 return AROS_UFC5(APTR
, ((struct IntExecBase
*)SysBase
)->PlatformData
.realRawDoFmt
,
66 AROS_UFCA(CONST_STRPTR
, fmt
, A0
),
67 AROS_UFCA(APTR
, args
, A1
),
68 AROS_UFCA(VOID_FUNC
, putch
, A2
),
69 AROS_UFCA(APTR
, putptr
, A3
),
70 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
75 AROS_LH3(APTR
, SetFunction
,
76 AROS_LHA(struct Library
*, library
, A1
),
77 AROS_LHA(LONG
, funcOffset
, A0
),
78 AROS_LHA(APTR
, newFunction
, D0
),
79 struct ExecBase
*, SysBase
, 70, Exec
)
85 D(bug("SetFunction(%s, -%lx, %lx) = ", (ULONG
)library
->lib_Node
.ln_Name
, -funcOffset
, (ULONG
)newFunction
));
88 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
89 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
91 This also effectively limits the max offset to 32k, but this limit was
92 already in the original, though not really documented.
94 What happens is this: the prototype for the funcOffset says it is a
95 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
96 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
97 offset, without sign-extending to the upper 16 bits, in fact without
98 even clearing them. These high 16 bits will therefore contain garbage:
100 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
101 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
102 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
103 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
104 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
105 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
107 In my [ldp] opinion, the autodoc should never have said that only A0.W
108 is used for the funcOffset, while specifying a "long" in the prototype.
109 This will stay broken and this fix will stay here until we fix
112 if (funcOffset
& 0x00008000)
114 funcOffset
|= 0xffff0000;
118 funcOffset
&= 0x0000ffff;
121 /* AOS 3.1's locale.library wants to trample over Exec/RawDoFmt.
122 * Since the replacement does not understand the 'magic' AROS
123 * RAWFMTFUNC_xxxx vectors, we need to install a wrapper to
124 * translate those to real functions.
126 * This should not effect AROS usage of SetFunction() of
127 * RawDoFmt, as it will only end up adding about 16 m68k
128 * instructions of overhead.
130 if (library
== (APTR
)SysBase
&& funcOffset
== (-87 * LIB_VECTSIZE
)) {
131 ((struct IntExecBase
*)SysBase
)->PlatformData
.realRawDoFmt
= newFunction
;
132 newFunction
= myRawDoFmt
;
136 Arbitrate for the jumptable. This isn't enough for interrupt callable
137 functions - but it need not be.
141 /* Mark the library as changed. */
142 library
->lib_Flags
|=LIBF_CHANGED
;
144 /* The following section is coded like this (instead of using the macros),
145 because else gcc will output 64-bit muls instructions, that are not
146 present on the 68060 (and will crash it). It's faster this way, too. :) */
147 vecaddr
= (APTR
)((ULONG
)library
+ funcOffset
);
149 /* Get the old vector pointer */
150 ret
= (APTR
)*(ULONG
*)(((ULONG
)vecaddr
)+2);
152 /* Set new vector and jmp instruction */
153 *(UWORD
*)vecaddr
= 0x4ef9;
154 *(ULONG
*)(((ULONG
)vecaddr
)+2) = (ULONG
)newFunction
;
159 /* Can't use this because there are broken programs that
160 * copy code and then call SetFunction().
162 CacheClearE(vecaddr
,LIB_VECTSIZE
,CACRF_ClearI
|CACRF_ClearD
);
165 /* Arbitration is no longer needed */
168 /* Sum the library up again */
171 D(bug("%lx\n", ret
));