Updated PCI IDs to latest snapshot.
[tangerine.git] / rom / exec / setfunction.c
blob7f10b2916e424f0cab51798cc9f8302d624028fa
1 /*
2 Copyright © 1995-2008, 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 <aros/libcall.h>
11 #include <proto/exec.h>
12 #include "exec_debug.h"
14 #ifndef DEBUG_SetFunction
15 # define DEBUG_SetFunction 0
16 #endif
17 #undef DEBUG
18 #if DEBUG_SetFunction
19 # define DEBUG 1
20 #endif
21 #include <aros/debug.h>
22 #undef kprintf
24 /*****************************************************************************
26 NAME */
28 AROS_LH3(APTR, SetFunction,
30 /* SYNOPSIS */
31 AROS_LHA(struct Library *, library, A1),
32 AROS_LHA(LONG, funcOffset, A0),
33 AROS_LHA(APTR, newFunction, D0),
35 /* LOCATION */
36 struct ExecBase *, SysBase, 70, Exec)
38 /* FUNCTION
39 Replaces a certain jumptable entry with another one. This function only
40 Forbid()s taskswitching but doesn't Disable() interrupts. You have
41 to do your own arbitration for functions which are callable from
42 interrupts.
44 INPUTS
45 library - Pointer to library structure.
46 funcOffset - Offset of the jumpvector from the library base address in
47 bytes. It's the negative LVO (library vector offset)
48 multiplied with LIB_VECTSIZE.
49 newFunction - New jumptable entry (pointer to the new function).
51 RESULT
52 Old jumptable entry (pointer to the old function).
54 NOTES
55 While it's more or less safe to patch a library vector with
56 SetFunction() it's not possible to safely remove the patch later.
57 So don't use this function if it can be avoided.
59 EXAMPLE
60 Patch of the function Open() from dos.library:
61 You can find the LVO of 5 in clib/dos_protos.h.
62 SetFunction(DOSBase, -5 * LIB_VECTSIZE, NewOpen);
63 NewOpen must be prepared with AROS_UFH macros.
65 BUGS
66 On native builds, this contains a hack to fix dos.library/ramlib
67 attempts to setfunction exec functions. Because of this, a funcOffset
68 of more than 32 kB be truncated. This hack will also fix other programs
69 only using the lower 16 bits of funcOffset and leaving garbage in the
70 upper 16 bits. These programs should be fixed.
72 SEE ALSO
73 MakeLibrary(), MakeFunctions(), SumLibrary()
75 INTERNALS
77 ******************************************************************************/
79 AROS_LIBFUNC_INIT
80 APTR ret;
81 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
82 ULONG *vecaddr;
83 #endif
85 D(bug("SetFunction(%s, %lx, %lx) = ", (ULONG)library->lib_Node.ln_Name, funcOffset, (ULONG)newFunction));
87 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
89 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
90 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
92 This also effectively limits the max offset to 32k, but this limit was
93 already in the original, though not really documented.
95 What happens is this: the prototype for the funcOffset says it is a
96 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
97 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
98 offset, without sign-extending to the upper 16 bits, in fact without
99 even clearing them. These high 16 bits will therefore contain garbage:
101 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
102 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
103 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
104 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
105 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
106 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
108 In my [ldp] opinion, the autodoc should never have said that only A0.W
109 is used for the funcOffset, while specifying a "long" in the prototype.
110 This will stay broken and this fix will stay here until we fix
111 dos.library/ramlib.
113 if (funcOffset & 0x00008000)
115 funcOffset |= 0xffff0000;
117 else
119 funcOffset &= 0x0000ffff;
122 #else
123 /* Vector pre-processing for non-native machines: */
124 funcOffset = (-funcOffset) / LIB_VECTSIZE;
126 #endif
129 Arbitrate for the jumptable. This isn't enough for interrupt callable
130 functions - but it need not be.
132 Forbid();
134 /* Mark the library as changed. */
135 library->lib_Flags|=LIBF_CHANGED;
137 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
138 /* The following section is coded like this (instead of using the macros),
139 because else gcc will output 64-bit muls instructions, that are not
140 present on the 68060 (and will crash it). It's faster this way, too. :) */
141 vecaddr = (APTR)((ULONG)library + funcOffset);
143 /* Get the old vector pointer */
144 ret = (APTR)*(ULONG *)(((ULONG)vecaddr)+2);
146 /* Set new vector and jmp instruction */
147 *(UWORD *)vecaddr = 0x4ef9;
148 *(ULONG *)(((ULONG)vecaddr)+2) = (ULONG)newFunction;
150 #else /* non-native section follows */
151 /* Get old vector. */
152 ret = __AROS_GETVECADDR (library, funcOffset);
154 /* Don't forget to initialise the vector, or else there would be no actual
155 assembler jump instruction in the vector */
156 __AROS_INITVEC (library, funcOffset);
158 /* Write new one. */
159 __AROS_SETVECADDR (library, funcOffset, newFunction);
161 #endif /* end if system specific sections */
163 #if 1
164 /* And clear the instruction cache. */
165 /* Simply clear the entire cache... */
166 CacheClearU();
167 #else
168 /* ...or clear the vector address range specifically */
169 CacheClearE (__AROS_GETJUMPVEC(library,funcOffset),LIB_VECTSIZE,CACRF_ClearI|CACRF_ClearD);
170 #endif
172 /* Arbitration is no longer needed */
173 Permit();
175 /* Sum the library up again */
176 SumLibrary(library);
178 D(bug("%lx\n", ret));
180 /* All done. */
181 return ret;
182 AROS_LIBFUNC_EXIT
183 } /* SetFunction */