|
| |
| |
| |
|
|
|
Online members:
12 guests are online.
You are an Anonymous user. You can register for free by clicking here. |
|
|
| |
| |
| |
| |
| |
| |
UtilityBase needs your
help!
How to install a hardware interrupt by Alfkil Thorbjørn Wennermark Link: How to install a hardware interrupt (c)
I was looking for a way to install a genuine hw interrupt, and this code is the proper way to do so. Thanks to Steven Solie, Thomas Frieden, Jörg Strohmayer and Colin Wenzel.
When trying to install an exec interrupt handler, I quickly realised,
that the IExec->AddIntServer didn't really do the job. All the
trapnumbers defined in exec/interrupts.h will make this
function fail, except for TRAPNUM_ILLEGAL_INSTRUCTION, that has
no relevance on ppc machines.
After some (a lot of) guidance from the real people, I have come up
with this example, that uses SetIntVector to install a global
interrupt handler for that particular interrupt. Beware, when you use
SetIntVector, you _have to_ manually call the old interrupt handler
(returned from SetIntVector) if you don't want your entire system
to go boom!
Also, if you are trying to catch exceptions from a specific task (eg.
for debugging purposes) you should use the AddDebugHook
function from the exec debug interface (more on this in a future
article).
Here is the example:
                                
/* realinterrupt.c - HW interrupt example code. Edited and updated for amigaos 4 by Alfkil T. Wennermark 2010 Edited and bug-tested by Steven Solie.
Thanks to: Steven Solie, Jörg Strohmayer, Thomas Frieden and Colin Wenzel :-) */
/* REMARK: On a SAM/SAM-flex system, the returned counter will be a very large number. We have yet to figure out, why this is. On AmigaOne's it will be 1 as expected. */
#include <exec/types.h> #include <proto/exec.h> #include <proto/dos.h>
#include <exec/memory.h> #include <exec/interrupts.h>
#include <dos/dos.h>
#include <stdio.h>
uint32 *beef;
struct IData {
   uint32 counter;
   struct Interrupt *oldinterrupt; };
struct IData *idata;
#if 0 //This will not work, because it doesn't call the old interrupt asm ( " .globl icoden" "     n" "icode:   n" " lwz %r3, 0(%r5) n" " addi %r3, %r3, 5n" " stw %r3, 0(%r5) n" " li %r3, 1 n" " blr   n" ); #endif
ULONG icode( struct ExceptionContext *context, struct ExecBase *sb, APTR trapData) {
   struct IData *d = (struct IData *)trapData;
   struct Interrupt *oldi = d->oldinterrupt;
   d->counter++;
   //NB-NB-NB: You _need_ to call the old interrupt, otherwise you will go boom!
   typedef uint32 (*OLDVEC)();
   return ((OLDVEC)oldi->is_Code)(context, sb, oldi->is_Data); }
int main() {
   enum enTrapNumbers trapnumber = TRAPNUM_DATA_SEGMENT_VIOLATION;
   if (!(idata = IExec->AllocMem(sizeof(struct IData), MEMF_SHARED | MEMF_CLEAR)))
   return RETURN_FAIL;
   struct Interrupt *interrupt = IExec->AllocSysObjectTags(ASOT_INTERRUPT,
   ASOINTR_Code, icode,
   ASOINTR_Data, idata,
   TAG_END);
   if (interrupt == NULL)
   {
       IExec->FreeMem (idata, sizeof (struct IData));
       return(-20);
   }
   interrupt->is_Node.ln_Pri = -1;
   interrupt->is_Node.ln_Name = "my personal interrupt";
   //printf("icode = %#08xn", icode (NULL, NULL, idata));
   //printf("counter = %dn", idata->counter);
   printf("calling AddIntServer...n");
   fflush(stdout);
   // IExec->Forbid();
   idata->oldinterrupt = IExec->SetIntVector(trapnumber, interrupt);
   // IExec->Permit();
   if(!idata->oldinterrupt)
   {
       printf("server not installed!n");
   }
   else
   {
       printf("server installedn");
       fflush(stdout);
       idata->counter = 0;
       //#if 0
       /* cause a data storage violation: */
       beef = (uint32 *)0;
       *beef = 0L;
       //#endif
       IDOS->Delay(10);
       printf("counter = %dn", idata->counter);
       /* Remember to restore the old interrupt vector, or you will die ;-) */
       IExec->SetIntVector(trapnumber, idata->oldinterrupt);
   }
   IExec->FreeSysObject(ASOT_INTERRUPT, interrupt);
   IExec->FreeMem (idata, sizeof (struct IData));
   return 0; }
|
|
| Last poster |
Message |
|
Posted: 2010-06-15 06:09 · Edited by: Hypex
Hi Alfkil.
I also had the same problem myself and enquired of Thomas at the time. It is unfortunate that AddIntServer() won't work as the SetIntVector() solution is a bit permanent and not as multitasking friendly.
It does work for vertical blanking interrupts, however. Even with 68K.
I'd like to add that an early version of AllocSysObjectTags(), at least from OS4.0 had a bug where it did not clear the memory it returned for the struct Interrupt. As we usually set the fields ourselves this would usually not be a problem but I found that the Node fields were trashed with random data and that made it a problem!
I worked around this by specifying ASOT_MemoryOvr, MEMF_PUBLIC | MEMF_CLEAR. If this is no longer necessary then that is good. :-)
Given the above code, it's a useful skeleton for catching illegal memory access, or even possibly custom chip space access for emulation. ;-)
I am hoping in the future that we will be provided access to such features, being able to add our own interrupt safely for this. Or even use the MMU API to do it at an equally safe level. Of course, this is the reason that no such mechanism was said to exist, and why we have to "hack" it into the system because the OS4 developers don't want us touching this stuff and risking system instability with core low level functions. |
|
|
|