Home Products Documents links News Events Tech Info

Modules in C

From: enevill@acorn.co.uk (Edward Nevill)
Subject: Re: Modules in C
Date: 4 Oct 91 14:01:06 GMT

In article <1991Oct01.212021.16581@demon.co.uk> pmoore@cix.compulink.co.uk (Paul Moore) writes:

>The second problem is more of a pain. I have worked out that I should
>declare my vector handler to CMHG as an IRQ handler, so that I get the
>proper veneer round my code. BUT... the vector I want to claim is (you
>guessed it!) OS_ReadLine, which requires the C flag to be set on exit
>based on the results of the call. As far as I can see, the standard
>veneer does not allow the setting of flags on return.
>As far as I can see, the only way round this is to write my own entry
>veneer for the handler. However, I'm not 100% sure what the 'standard'
>veneer does. I can probably work it out by disassembling the code
>generated by CMHG, but can anybody *tell* me what it does - to save me
>some work? If so, I'd be very grateful. Also, maybe later versions of
>CMHG would benefit from an extra keyword 'irq-handlers-c' or some such?

irq_entry       STMDB   sp!, {r0-r9, sl, fp, lr}  ; Save regs on IRQ | SVC stack
                MOV     r0, sp           ; Set up _kernel_swi_regs * argument
+               ADD     r2, sp, #12 * 4  ; Set up pointer to carry arg (= LR!!!)
                MOV     r6, pc
                BIC     r6, r6, #3
                TEQP    r3, #3           ; To SVC mode, preserve IRQ / FIQ state
                MOV     fp, #0           ; Halt C backtrace at this stack level
                MOV     r7, lr           ; Save SVC lr
                MOV     sl, sp, LSR #20
                MOV     sl, sl, ASL #20  ; Get LWM of SVC stack
                LDMIA   sl, {r4, r5}     ; Save static data relocations across fn call
                MOV     r1, r12          ; Set up private workspace argument
                LDR     r12, [r12]       ; Get pointer to static relocations for module
                LDMIB   r12, {r12, lr}   ; IB skips first word
                STMIA   sl, {r12, lr}    ; Set up static data relocations
                ADD     sl, sl, #512+40  ; 40 = size of stack chunk structure
                BL      c_function       ; Do the function
                SUB     sl, sl, #512+40  ; Point back to base of SVC stack
                STMIA   sl, {r4, r5}     ; Restore old static data relocations
                MOV     lr, r7           ; Restore SVC lr
                TEQP    r6, #0           ; Back to entry mode
                CMPS    r0, #0           ; Intercept?
                LDMNEIA sp!, {r0-r9, sl, fp, pc}^ ; No (carry arg will not be written!!!)
-               LDMIA   sp!, {r0-r9, sl, fp, lr, pc}^ ; Yes
+               LDMIA   sp!, {r0-r9, sl, fp, ip, lr} ; Yes (ip = carry value to ret)
+               BIC     lr, lr, #1:SHL:29
+               CMP     ip, #0
+               ORRNE   lr, lr, #1:SHL:29
+               MOVS    pc, lr

The veneer genererated for an IRQ handler by cmhg is something like the above
without the '+' lines. Remove the '-' line and add the '+' lines to produce a
veneer which allows you to return the carry flag.

The declaration the a handler using this looks something like

int c_function(_kernel_swi_regs *r, void *pw, int *carry);

NOTE: you must not write the carry arg unless you are intercepting the call
(ie you are returning 0 from c_function). Doing so will lead to disaster
(it will continue executing at the address you write to carry, so if you
write 0 it will continue executing at location 0!!!). I may consider making
this more robust in a later version.

To claim the vector in your init code

extern int irq_entry;

_kernel_oserror *user_init(char *cmd_tail, int podule_base, void *pw)
    _kernel_swi_regs r;
    r.r[0] = 0x0e; /* ReadLineV */
    r.r[1] = (int)&irq_entry;
    r.r[2] = (int)pw;
    _kernel_swi(OS_Claim, &r, &r);
    return 0;

NOTE: If you claim a vector in your initialisation code like this you must
either return 0 indicating no error or release the vector before returning an
error (your finalisation is not called if there is an error in initialisation).

Have fun,