Support rastport clipping rectangle for layerless rastports
[tangerine.git] / rom / exec / setfunction.c
blob40ac291b0295001478f285e25a9e070771441f0a
1 /*
2 Copyright © 1995-2001, 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.
48 newFunction - New jumptable entry (pointer to the new function).
50 RESULT
51 Old jumptable entry (pointer to the old function).
53 NOTES
54 While it's more or less safe to patch a library vector with
55 SetFunction() it's not possible to safely remove the patch later.
56 So don't use this function if it can be avoided.
58 EXAMPLE
60 BUGS
61 On native builds, this contains a hack to fix dos.library/ramlib
62 attempts to setfunction exec functions. Because of this, a funcOffset
63 of more than 32 kB be truncated. This hack will also fix other programs
64 only using the lower 16 bits of funcOffset and leaving garbage in the
65 upper 16 bits. These programs should be fixed.
67 SEE ALSO
68 MakeLibrary(), MakeFunctions(), SumLibrary().
70 INTERNALS
72 ******************************************************************************/
74 AROS_LIBFUNC_INIT
75 APTR ret;
76 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
77 ULONG *vecaddr;
78 #endif
80 D(bug("SetFunction(%s, %lx, %lx) = ", (ULONG)library->lib_Node.ln_Name, funcOffset, (ULONG)newFunction));
82 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
84 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
85 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
87 This also effectively limits the max offset to 32k, but this limit was
88 already in the original, though not really documented.
90 What happens is this: the prototype for the funcOffset says it is a
91 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
92 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
93 offset, without sign-extending to the upper 16 bits, in fact without
94 even clearing them. These high 16 bits will therefore contain garbage:
96 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
97 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
98 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
99 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
100 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
101 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
103 In my [ldp] opinion, the autodoc should never have said that only A0.W
104 is used for the funcOffset, while specifying a "long" in the prototype.
105 This will stay broken and this fix will stay here until we fix
106 dos.library/ramlib.
108 if (funcOffset & 0x00008000)
110 funcOffset |= 0xffff0000;
112 else
114 funcOffset &= 0x0000ffff;
117 #else
118 /* Vector pre-processing for non-native machines: */
119 funcOffset = (-funcOffset) / LIB_VECTSIZE;
121 #endif
124 Arbitrate for the jumptable. This isn't enough for interrupt callable
125 functions - but it need not be.
127 Forbid();
129 /* Mark the library as changed. */
130 library->lib_Flags|=LIBF_CHANGED;
132 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
133 /* The following section is coded like this (instead of using the macros),
134 because else gcc will output 64-bit muls instructions, that are not
135 present on the 68060 (and will crash it). It's faster this way, too. :) */
136 vecaddr = (APTR)((ULONG)library + funcOffset);
138 /* Get the old vector pointer */
139 ret = (APTR)*(ULONG *)(((ULONG)vecaddr)+2);
141 /* Set new vector and jmp instruction */
142 *(UWORD *)vecaddr = 0x4ef9;
143 *(ULONG *)(((ULONG)vecaddr)+2) = (ULONG)newFunction;
145 #else /* non-native section follows */
146 /* Get old vector. */
147 ret = __AROS_GETVECADDR (library, funcOffset);
149 /* Don't forget to initialise the vector, or else there would be no actual
150 assembler jump instruction in the vector */
151 __AROS_INITVEC (library, funcOffset);
153 /* Write new one. */
154 __AROS_SETVECADDR (library, funcOffset, newFunction);
156 #endif /* end if system specific sections */
158 #if 1
159 /* And clear the instruction cache. */
160 /* Simply clear the entire cache... */
161 CacheClearU();
162 #else
163 /* ...or clear the vector address range specifically */
164 CacheClearE (__AROS_GETJUMPVEC(library,funcOffset),LIB_VECTSIZE,CACRF_ClearI|CACRF_ClearD);
165 #endif
167 /* Arbitration is no longer needed */
168 Permit();
170 /* Sum the library up again */
171 SumLibrary(library);
173 D(bug("%lx\n", ret));
175 /* All done. */
176 return ret;
177 AROS_LIBFUNC_EXIT
178 } /* SetFunction */