In some cases, kernel callouts need access to static read/write storage, in
particular to share information with other kernel callouts.
Because kernel callout code is position-independent (see Common characteristics), it cannot
have static read/write storage. However, you can assign a small amount a memory at
the end of the system page to a kernel callout (or multiple kernel callouts) to use as
read/write storage.
You can use the CALLOUT_START macro's second argument to specify the
address of a four-byte variable that contains the amount of read/write storage (in
bytes) the callout needs. For example, in the code snippet below:
- rw_interrupt has the address of the location with the number
of bytes of storage required.
- Since the location referenced by rw_interrupt contains the
value 4, the startup library allocates four bytes at the end of
the system page.
- The library uses the patcher routine's rw_offset argument to
pass the offset of the allocated memory (see Patcher routines)
to this routine.
- The patcher routine modifies the initial instruction of the callout to refer
to the appropriate offset, so that while the callout is executing, the
t3 register contains a pointer to the read/write
storage.
Here is the code snippet:
rw_interrupt:
.long 4
patch_interrupt:
add a1,a1,a2
j ra
sh a3,0+LOW16(a1)
/* Mask the specified interrupt */
CALLOUT_START(interrupt_mask_my_board, rw_interrupt, patch_interrupt)
/*
* Input Parameters :
* a0 - syspage_ptr
* a1 - Interrupt Number
* Returns:
* v0 - error status
*/
...
CALLOUT_END(interrupt_mask_my_board)
Sharing data between kernel callouts
If you set aside read/write static storage at the end of the system page for one
kernel callout, you can use this area to pass data between callouts. The
startup library passes the same rw_offset value to the patchers
for all callouts that share the same address in their
CALLOUT_START macro's second argument.
For example, because the patchers for the following callouts have the same
rw_offset argument value passed to
patch_interrupt(), they share the same read/write storage,
which they can use to exchange data as needed:
CALLOUT_START(interrupt_mask_my_board, rw_interrupt, patch_interrupt)
....
CALLOUT_END(interrupt_mask_my_board)
CALLOUT_START(interrupt_unmask_my_board, rw_interrupt, patch_interrupt)
....
CALLOUT_END(interrupt_unmask_my_board)
CALLOUT_START(interrupt_eoi_my_board, rw_interrupt, patch_interrupt)
....
CALLOUT_END(interrupt_eoi_my_board)
CALLOUT_START(interrupt_id_my_board, rw_interrupt, patch_interrupt)
....
CALLOUT_END(interrupt_id_my_board)