Allocating read/write storage

In some cases, kernel callouts need access to some static read/write storage, in particular to be able 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 kernel callout needs. For example, in the code snippet below:

  1. rw_interrupt has the address of the location with the number of bytes of storage required.
  2. Since the contents at the location referenced by rw_interrupt is 4, the startup library allocates four bytes at the end of the system page.
  3. The library uses the patcher routine's rw_offset argument to pass to the patcher the offset to this allocated memory (see Patcher routines).
  4. The patcher routine then modifies the initial instruction of the kernel callout 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 kernel callouts. The startup library passes the same rw_offset value to the patchers for all the kernel callouts that share the same address in their CALLOUT_START macro's second argument.

For example, because the patchers for the following kernel callouts have the same rw_offset argument value passed to patch_interrupt(), they share the same read/write storage, which they can use to share 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)